AOP 概念
切面(Advisor):是AOP中的一个术语,表示从业务逻辑中分离出来的横切逻辑,比如性能监控,日志记录,权限控制等
增强: 增强代码的功能的类,横切到代码中。
目标:目标方法(JDK代理)或目标类(CGLIB代理)
代理:JDK代理,CGLIB代理。或是通过 ProxyFactory 类生产。
切点:通过一个条件来匹配要拦截的类,这个条件称为切点。如拦截所有带 Controller 注解的类。增强的条件。
连接点:作为增强方法的入参,可以获取到目标方法的信息。
演示:
引入 jar 包
引入 Spring 配置文件 :有两处的aop内容
注入Mybefore 和 MyImpl
<bean id="mybefore" class="com.kgc.aop.demo.Mybefore"></bean>
<bean id="myImpl" class="com.kgc.aop.demo.MyImpl"></bean>
注: MyImpl 位 具体实现类 , Mybefore 是实现这个实现类时 插入 的一些 跟具体实现类无任何关系的操作
下面是 AOP 的XML配置具体操作
<!-- 代理已经配置好了 -->
<!-- 标签内不是aop的配置 -->
<aop:config>
<!-- 切入点 -->
<aop:pointcut id="myPointCut" expression="execution(* com.kgc.aop.demo.MyImpl.test01(..))" />
<!-- 切面 -->
<aop:aspect ref="mybefore">
<!-- 通知 -->
<aop:before method="before" pointcut-ref="myPointCut" />
<aop:after method="after" pointcut-ref="myPointCut" />
<aop:after-returning method="returning" pointcut-ref="myPointCut" />
<aop:after-throwing method="throwing" pointcut-ref="myPointCut" />
<aop:around method="around" pointcut-ref="myPointCut" />
</aop:aspect>
</aop:config>
AOP的通知标签 : Weaving(织入):对方法进行增强
before 在某连接点之前执行的通知
after-throwing 在方法抛出异常退出时执行的通知
after-returning 在某连接点正常完成之后通知(如果抛出异常就不执行到)
after 在某连接点退出时执行的通知(一定会执行)
around 包围一个连接点的通知
切入点: 作用: 匹配连接点
增强: 增强代码的功能的类,横切到代码中。
切入点表达式语法:
execution(
Modifiers-pattern? --方法操作权限【可选】
Ret-type-pattern --返回值 【必选】
declaring-type-pattern? --方法所在包 【可选】
name-pattern (param-pattern) --方法名(参数) 【必选】
throws-pattern? --异常 【可选】
)
// 表示com.kgc.aop.demo 包下任意类和任意方法
execution(* com.kgc.aop.demo.MyImpl.test01(..))
// 表示任意多个子包
execution(* com..*.*(*))
切入点表达式进一步剖析
* : 1、表示任意类和包名
2、表示任意方法名
3、表示任意一个类型的参数
.. : 1、在类型模式中,表示任意多个子包
2、对参数没有任何限制
+ : 1、匹配指定类型的子类型(子类)
@AspectJ 支持
1、 是注解形式的 AOP 方便使用 简化配置
2、 AspectJ 是Spring AOP 的默认 实现工具
注意 : 使用注解是为了简化配置(而不是减掉配置)
示例
1、开启注解支持
<!-- 开启AOP 的注解支持 -->
<aop:aspectj-autoproxy />
2、在AOP 代理源上加入 AOP支持 加上 @Aspect 标签
/*
<aop:pointcut id="myPointCut" expression="execution(* com..*.*(com.kgc.aop.demo.Child+))" />
<aop:aspect ref="mybefore">
<aop:before method="before" pointcut-ref="myPointCut" />
</aop:aspect>
*/
@Aspect
public class AnnoProxy {
...
}
3、将AOP 代理和目标对象注入到Spring
@Pointcut(value="execution(* com..*.*(int))")
public void pointCut(){}
@Pointcut(value="within(com.kgc.aop.annocation.TargetImpl)")
public void pointCut2(){}
@Before(value="pointCut2()")
public void methodBefore(JoinPoint jp){
System.out.println("这是方法开始之前!入参jp="+jp.getArgs()[0]);
System.out.println("这是方法开始之前!签名="+jp.getSignature());
}
@After(value="pointCut2() && args(a) ")
public void methodAfter(int a){
System.out.println("这是方法执行之后,入参a="+a);
}
@AfterThrowing(value="pointCut2()",throwing="e")
public void afterThrowing(Exception e){
System.out.println("抛出异常啦,e="+e.getMessage());
}
@Around(value="pointCut2()")
public void around(ProceedingJoinPoint pjp){
System.out.println("around~!");
try {
Object result = pjp.proceed();
System.out.println("result = "+result);
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("方法执行之后!");
}
around 详解:
当执行around 是时候 是不跳入 我们的目标实现 方法的, 只会执行 before 操作,其他操作全部不执行,
不过我们可以 用 ProceedingJoinPoint 中的 .proceed() 方法,我养我们就可以跳入 执行了。
传参
1、使用joinPoint 传参
如上面的实例
注:ProceedingJoinPoint 是 JoinPoint 的子类
2、agrs
通知的执行顺序
1、继承 Order
public class OrderProxy implements Ordered
2、重写方法 , 赋值权重
@Override //权重
public int getOrder() {
// TODO Auto-generated method stub
return 20;
}
AOP 设计实战 ( 老师的经验)
- AOP 尽量拦截方法,而不是字段
- AOP 的使用用遵循如下原则:
大部分或全部模块都需要使用的通用功能
预计未来功能扩展的可能性比较大的地方
- AOP 设计应遵循正交原则
先进的后出 后进的先出
- 尽量对粗粒度对象使用 AOP