复习Spring第三课SpringAop
Aop
不修改代码得前提下,增加方法
一,为什么要用aop?
(1)代码混乱:越来越多得非业务需求(日志和验证等)加入后,原有得业务方法急剧膨胀,每个方法在处理核心逻辑得同时还必须兼顾其他多个关注点。
(2)代码冗余:以日志需求为例,直为了满足这个单易需求,就不得不在多个模块(方法)里重复相同得日志代码,如果日志需求发生变化,必须修改所有的模块。
二,Aop简介
(1)Aop(Aspect-Oriented Programming)面向切面编程:是一种新的方法论,是对传统OOP(Object-Oriented Programming,面向对象编辑)的补充。
(2)AOP的主要编程对象是切面(aspect),而且切面模块化横切关注点(横切关注点即具体需求)。
(3)在应用AOP编程时,仍需要定义公共功能。但可以明确的定义功能在哪里,以什么方式和应用,并且不必修改受影响的类。这样一来横切关注点就被模块化导特殊的对象(切面)里。
(4)AOP的好处:
每个事物逻辑位于一个位置,代码不分散,便于维护和升级业务模块更简洁,只包含核心业务代码。
三,图解AOP
四,Aop重要术语
(1)通知:切面必须要完成得工作,切面中得每一个方法都有被称为一个通知
前置通知@Befter
后置通知@After
返回通知@AfterRunning
异常通知@AfterThrowing
环绕通知@Around
(2)目标:bei通知得对象,即院有得最基本得功能
(3)代理:切面+目标得整体
(4)连接点:程序执行得某个特定位置,由方法加方位构成,例如:add方法,执行之前
(5)切点:每个类都拥有多个连接点,Aop通过切点啊定位到特定得连接带你,切点和连接点不是一对一得关系,一个切点匹配多个连接点
五,Aop写法
1,配置文件中写
```java
<!-- 配置aop自动代理处理方式 -->
<aop:aspectj-autoproxy/>
<!-- 给我们自定义的aop切面类创建出相应的bean,交给spring管理-->
<bean id="aopAspect" class ="com.haina.spring.aop.AopAspect"/>
<!-- 用来配置我们要给那个类的哪写方法增加aop切面-->
<aop:config>
<!-- 使用表达式来匹配我么需要增加切面方法,pointcut是一个切点,通用改切点使用得表达式可以找到匹配得方法-->
<!-- 给公共得方法增加-->
<aop:pointcut id="cal" expression="execution(public* com.haina.spring.aop.CalculatorImpl.*(..))"/>
<aop:aspect ref="aopAspect">
<!-- 通过cal这个切点找到得方法,在执行前需要调用aopAspect对象中得before方法-->
<!-- pointcut-ref属性用来配置 需要使用得切点得bean method属性用来配置需要调用切面得那个方法-->
<!-- 动态代理模式-->
<aop:before method="before" pointcut-ref="cal"/>
<!-- 在方法运行之后执行after方法,即使方法出现了异常,这个逻辑仍然会执行-->
<aop:after method="after" pointcut-ref="cal"/>
<!-- after-returing 在运行成功之后才会执行,如果出现异常则不会执行,后面得也不会执行 ,result参数-->
<aop:after-returning method="afterRet" pointcut-ref="cal" returning="result"/>
<!-- 只有在方法出现异常得时候才会,触发这个通知,后面得不会执行-->
<aop:after-throwing method="afterException" pointcut-ref="cal"/>
<!-- 可以在方法执行前执行后分别加上-->
<aop:around method="round" pointcut-ref="cal"/>
</aop:aspect>
</aop:config>
AopAspect 类
//aop类
public class AopAspect {
// JoinPoint P一定要大写,p小写是另一个类
public void before(JoinPoint joinPoint){
// 获取被代理得方法名
String name = joinPoint.getSignature().getName();
// 用来获取被代理得方法参数值列表
Object[] params = joinPoint.getArgs();
for(Object o :params){
Integer i = (Integer) o;
if(i<0){
throw new RuntimeException(name+"方法得参数不允许负数");
}
}
System.out.println(name +"方法执行");
}
public void after(JoinPoint joinPoint){
// 获取被代理得方法名
String name = joinPoint.getSignature().getName();
System.out.println(name+"方法执行完成!!!");
}
public void afterRet(JoinPoint joinPoint,int result){
// 获取被代理得方法名
String name = joinPoint.getSignature().getName();
System.out.println(name+"方法执行成功"+",方法执行结果:"+result);
}
public void afterException(JoinPoint joinPoint){
// 获取被代理得方法名
String name = joinPoint.getSignature().getName();
System.out.println(name+"方法抛出了异常");
}
// 环绕通知,需要手动调用,环绕通知得方法根据被代理得方法来决定要不要加返回值
// 如果被代理得方法有返回值,则方法发必须也要加返回值
public Object round(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
System.out.println("环绕通知");
//调用被代理得方法
Object result = proceedingJoinPoint.proceed();
System.out.println("环绕通知结束,运行结果:"+result);
return result;
}
}
@Component //
public class CalculatorImpl implements Calculator {
public int add(int a, int b) {
return a+b;
}
public int sub(int a, int b) {
return a-b;
}
public int mul(int a, int b) {
return a*b;
}
public int div(int a, int b) {
return a/b;
}
}
public class AopTest {
public static void main(String[] args) {
// 创建spring全局对象,加载配置文件,用来初始化spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过接口类型也可以获取到他实现类得对象
// 如果改接口有多个实现类,则不能这样写
Calculator c = ctx.getBean(Calculator.class);
int result = c.add(3,8);
System.out.println(result);
c.div(2,1);
c.mul(3,5);
c.sub(6,4);
}
}
2,注解写法
//用注解写aop
@Aspect
@Component
public class AopAspect1 {
@Pointcut("execution(public* com.haina.spring.aop.CalculatorImpl.*(..))")
public void pointCut(){
}
// @Before("execution(public* com.haina.spring.aop.CalculatorImpl.*(..))")
// 这里可以符用表达式,注解里面得内容时带有@Pointcut注解得方法得方法名
@Before("pointCut()")
public void before(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
System.out.println(name+"方法被执行------");
}
// @After("execution(public* com.haina.spring.aop.CalculatorImpl.*(..))")
@After("pointCut()")
public void after(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
System.out.println(name+"方法执行完成------");
}
}
六,执行顺序
1,不抛出异常时的顺序
2,抛出异常时的顺序
上一篇: 多行文字垂直居中
推荐阅读
-
新手学习spring boot第三课
-
JPA学习 —— 第三课、spring整合JPA (完全版)
-
复习Spring第三课SpringAop
-
基于注解实现spring AOP 博客分类: spring框架 springaop
-
spring面试题 对DI , AOP概念的理解 博客分类: Spring springaop
-
spring面试题 对DI , AOP概念的理解 博客分类: Spring springaop
-
SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)(转载) 博客分类: Spring框架 aopspringaspectj
-
Spring AOP实现源码分析(一) 博客分类: spring springaop
-
Spring AOP 常用的四种实现方式 博客分类: 框架开发 springaop
-
spring源码学习系列4.2-spring aop原理-codes 博客分类: spring springaop设计模式