[toc]
aop的 实现
先添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
在spring中配置一下
@Configuration
@EnableAspectJAutoProxy
public class AspectConf {
}
aop的实现
@Component注入bean
@Aspect表示切面
@Pointcut 表示切点
@Aspect
@Component
public class AspectTest {
private static final Logger logger = (Logger) LoggerFactory.getLogger(AspectTest.class);
private long start;
@Pointcut(value = "@annotation(com.example.demo.controler.TestCon.*)")
public void timer(){}
//在方法执行前执行
@Before("timer()")
public void before() {
start = System.currentTimeMillis();
}
//在方法执行后执行
@After("timer()")
public void after() {
long now = System.currentTimeMillis();
logger.info("job took time {}s in summary"+(now - start) / 1000);
}
}
pointcut的表示
AspectJ匹配模式
- execution:用于匹配方法执行的连接点;
- within:用于匹配指定类型内的方法执行;
- this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
- target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
- args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
- @within:用于匹配所以持有指定注解类型内的方法;
- @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
- @args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
- @annotation:用于匹配当前执行方法持有指定注解的方法;
参考
切点表达式
execution([可见性] 返回类型 [声明类型].方法名(参数) [异常])
其中【】中的为可选,其他的还支持通配符的使用:
*:匹配所有字符
..:一般用于匹配多个包,多个参数
+:表示类及其子类
运算符有:&&、||、!
1)execution:用于匹配子表达式。
//匹配com.cjm.model包及其子包中所有类中的所有方法,返回类型任意,方法参数任意
@Pointcut("execution(* com.cjm.model..*.*(..))")
public void before(){}
2)within:用于匹配连接点所在的Java类或者包。
//匹配Person类中的所有方法
@Pointcut("within(com.cjm.model.Person)")
public void before(){}
//匹配com.cjm包及其子包中所有类中的所有方法
@Pointcut("within(com.cjm..*)")
public void before(){}
3) this:用于向通知方法中传入代理对象的引用。
@Before("before() && this(proxy)")
public void beforeAdvide(JoinPoint point, Object proxy){
//处理逻辑
}
4)target:用于向通知方法中传入目标对象的引用。
@Before("before() && target(target)
public void beforeAdvide(JoinPoint point, Object proxy){
//处理逻辑
}
5)args:用于将参数传入到通知方法中。
@Before("before() && args(age,username)")
public void beforeAdvide(JoinPoint point, int age, String username){
//处理逻辑
}
6)@within :用于匹配在类一级使用了参数确定的注解的类,其所有方法都将被匹配。
@Pointcut("@within(com.cjm.annotation.AdviceAnnotation)") - 所有被@AdviceAnnotation标注的类都将匹配
public void before(){}
7)@target :和@within的功能类似,但必须要指定注解接口的保留策略为RUNTIME。
@Pointcut("@target(com.cjm.annotation.AdviceAnnotation)")
public void before(){}
8)@args :传入连接点的对象对应的Java类必须被@args指定的Annotation注解标注。
@Before("@args(com.cjm.annotation.AdviceAnnotation)")
public void beforeAdvide(JoinPoint point){
//处理逻辑
}
9)@annotation :匹配连接点被它参数指定的Annotation注解的方法。也就是说,所有被指定注解标注的方法都将匹配。
@Pointcut("@annotation(com.cjm.annotation.AdviceAnnotation)")
public void before(){}
10)bean:通过受管Bean的名字来限定连接点所在的Bean。该关键词是Spring2.5新增的。
@Pointcut("bean(person)")
public void before(){}
通知参数
任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型(环绕通知需要定义第一个参数为ProceedingJoinPoint类型,它是 JoinPoint 的一个子类)。JoinPoint接口提供了一系列有用的方法,比如 getArgs()(返回方法参数)、getThis()(返回代理对象)、getTarget()(返回目标)、getSignature()(返回正在被通知的方法相关信息)和 toString()(打印出正在被通知的方法的有用信息)
aop的实现原理
AspectJ
aspectJ 是静态代理的方式,AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强。在编译阶段通过把AspectJ向代码中插入java代码来调用Aspect对象函数来实现.
spring AOP
Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
分为两种:
– JDK动态代理: 通过反射来接受被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
– CGLIB代理:可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理
– 目标类没有实现InvocationHandler接口和Proxy类接口,那么Spring AOP会选择使用CGLIB来动态代理目标类;
aop使用源码
- aop通知类型:
- @Before 前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。
- @After 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
- @AfterReturning 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。
- @Around 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。
- @AfterThrowing 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。
参考博客:https://www.cnblogs.com/lic309/p/4079194.html
参考博客:http://www.importnew.com/24305.html
发表回复