AOP基于BeanPostProcessor实现。
Spring在初始化后会去判断当前正在创建的Bean是不是需要进行AOP 操作,如果需要则会进行动态代理。
AOP代理对象
生产代理类—>代理对象—>代理对象target赋值(target=普通对象)
如何判断当前Bean对象是否需要进行AOP:
- 找出所有的切面Bean(使用@Aspect的Bean)【第一次解析后,会进行缓存】
- 遍历切面中的每个方法,看是否使用@Before、@After等注解。
- 如果使用,则逐个判断所对应的Pointcut是否和当前Bean对象的类是否匹配
- 如果匹配则表示当前Bean对象有匹配的的Pointcut,表示需要进行AOP,进行代理生成逻辑
- 把对应的代理方法(lambda表达)存放到三级缓存中
https://note.youdao.com/ynoteshare/index.html?id=f30e818e00f2c3eb6d4f26e6c0b70ade&type=note&_time=1664262640199
一、基本介绍
Advice分类
1. Before Advice:方法之前执行。
1. @Before。会被解析为AspectJMethodBeforeAdvice,实际上就是一个MethodBeforeAdvice
2. After returning advice:方法return后执行。
1. @AfterReturning。解析为:AspectJAfterReturningAdvice,实际上就是一个AfterReturningAdvice
3. After throwing advice:方法抛异常后执行。
1. @AfterThrowing。解析为AspectJAfterThrowingAdvice,实际上就是一个MethodInterceptor
4. After (finally) advice:方法执行完finally之后执行,这是最后的,比return更后。
1. @After。解析为AspectJAfterAdvice,实际上就是一个MethodInterceptor
5. Around advice:功能最强大的Advice,可以自定义执行顺序。
1. @Around。解析为AspectJAroundAdvice,实际上就是一个MethodInterceptor
Advisor
与Advice类似。用于指定需要代理的方法
一个Advisor由一个Pointcut(负责指定增强方法)和一个Advice(负责增强逻辑)组成。Pointcut指定需要被代理的逻辑(方法)。如果不能指定,则代理类中的方法都会被代理。
@Test
public void advisorTest(){
UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(new PointcutAdvisor() {
//指定需要增强方法(logout)
@Override
public Pointcut getPointcut() {
return new StaticMethodMatcherPointcut() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return method.getName().equals("logout");
}
};
}
//定义增强逻辑
@Override
public Advice getAdvice() {
return new org.aopalliance.intercept.MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
};
}
@Override
public boolean isPerInstance() {
return false;
}
});
ServiceInterface userService = (ServiceInterface) proxyFactory.getProxy();
userService.login();
userService.logout();
}
通过Advisor指定在执行loginout方法时,才有执行增强逻辑。
AOP概念
1. Aspect:表示切面。被@Aspect注解的类就是切面,可以在切面中去定义Pointcut、Advice等
2. Join point:表示连接点,表示一个程序在执行过程中的一个点。在Spring AOP中,一个连接点通常表示一个方法的执行。
3. Advice:表示通知,表示在一个特定连接点上所采取的动作。Advice分为不同的类型。Spring使用拦截器(Interceptor)实现Advice,并且在连接点周围维护一个Interceptor链
4. Pointcut:表示切点,用来匹配一个或多个连接点,Advice与切点表达式是关联在一起的,Advice将会执行在和切点表达式所匹配的连接点上
5. Introduction:可以使用@DeclareParents来给所匹配的类添加一个接口,并指定一个默认实现
6. Target object:目标对象,被代理对象
7. AOP proxy:表示代理工厂,用来创建代理对象的。在Spring Framework中,是JDK动态代理,或是CGLIB代理。
8. Weaving:表示织入,表示创建代理对象的动作,织入动作可以发生在编译时期(比如Aspejctj),或者运行时,比如Spring AOP
二、AOP实现由浅入深
1.利用Spring代理工厂完成逻辑增强
1.需要逐个指定代理对象。2.手动设置切入点
@Configurable
@ComponentScan("com.masterlu.ioc.aop")
public class AopDemoConfig {
@Bean
public MethodInterceptor methodInterceptor() {
return new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
Object proceed = invocation.proceed();
System.out.println("after");
return proceed;
}
};
}
@Bean
public ProxyFactoryBean userService(){
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(new UserService());
proxyFactoryBean.setInterceptorNames("methodInterceptor");
return proxyFactoryBean;
}
}
@Test
public void springAOPTest1() {
//因为UserService实现接口。所以产生JDK代理对象。只能使用接口类型
ServiceInterface userService = (ServiceInterface) applicationContext.getBean("userService");
userService.login();
}
2.利用BeanNameAutoProxyCreator批量设置
需要手动设置切入点。
@Configurable
@ComponentScan("com.masterlu.ioc.aop")
public class AopDemoConfig {
@Bean
public MethodInterceptor methodInterceptor() {
return new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
Object proceed = invocation.proceed();
System.out.println("after");
return proceed;
}
};
}
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
beanNameAutoProxyCreator.setBeanNames("userSe*");
beanNameAutoProxyCreator.setInterceptorNames("methodInterceptor");
beanNameAutoProxyCreator.setProxyTargetClass(true);
return beanNameAutoProxyCreator;
}
}
3.利用DefaultAdvisorAutoProxyCreator自动查找切入点
@ComponentScan("com.masterlu.ioc.aop")
public class AppConfig {
//指定切入点以及增强逻辑。
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.addMethodName("login");
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
defaultPointcutAdvisor.setPointcut(pointcut);
defaultPointcutAdvisor.setAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
method.invoke(target, args);
}
});
return defaultPointcutAdvisor;
}
// DefaultAdvisorAutoProxyCreator查找容器中所有Advisor实例
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
return defaultAdvisorAutoProxyCreator;
}
}
4.使用注解引入DefaultAdvisorAutoProxyCreator
@ComponentScan("com.masterlu")
//DefaultAdvisorAutoProxyCreator查找容器中所有Advisor实例
@Import(DefaultAdvisorAutoProxyCreator.class)
public class AppConfig {
//指定切入点以及增强逻辑。
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.addMethodName("login");
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
defaultPointcutAdvisor.setPointcut(pointcut);
defaultPointcutAdvisor.setAdvice(new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
method.invoke(target, args);
}
});
return defaultPointcutAdvisor;
}
}
DefaultPointcutAdvisor的功能可以使用注解(@Aspect、@Before、@After等注解)代替。
但是DefaultAdvisorAutoProxyCreator不能解析切面注解,需要使用AnnotationAwareAspectJAutoProxyCreator
5.利用注解设置注入点
@Component
@Aspect
public class DemoAspect {
@Pointcut("execution(* *.login(..))")
public void login() {
}
}
@ComponentScan("com.masterlu")
@EnableAspectJAutoProxy
public class AppConfig {
}
@EnableAspectJAutoProxy(本质引入AnnotationAwareAspectJAutoProxyCreator)