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,实际上就是一个MethodBeforeAdvice2. After returning advice:方法return后执行。1. @AfterReturning。解析为:AspectJAfterReturningAdvice,实际上就是一个AfterReturningAdvice3. After throwing advice:方法抛异常后执行。1. @AfterThrowing。解析为AspectJAfterThrowingAdvice,实际上就是一个MethodInterceptor4. After (finally) advice:方法执行完finally之后执行,这是最后的,比return更后。1. @After。解析为AspectJAfterAdvice,实际上就是一个MethodInterceptor5. Around advice:功能最强大的Advice,可以自定义执行顺序。1. @Around。解析为AspectJAroundAdvice,实际上就是一个MethodInterceptor
Advisor
与Advice类似。用于指定需要代理的方法
一个Advisor由一个Pointcut(负责指定增强方法)和一个Advice(负责增强逻辑)组成。Pointcut指定需要被代理的逻辑(方法)。如果不能指定,则代理类中的方法都会被代理。
@Testpublic void advisorTest(){UserService target = new UserService();ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);proxyFactory.addAdvisor(new PointcutAdvisor() {//指定需要增强方法(logout)@Overridepublic Pointcut getPointcut() {return new StaticMethodMatcherPointcut() {@Overridepublic boolean matches(Method method, Class<?> targetClass) {return method.getName().equals("logout");}};}//定义增强逻辑@Overridepublic Advice getAdvice() {return new org.aopalliance.intercept.MethodInterceptor() {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}};}@Overridepublic 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 {@Beanpublic MethodInterceptor methodInterceptor() {return new MethodInterceptor() {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("before");Object proceed = invocation.proceed();System.out.println("after");return proceed;}};}@Beanpublic ProxyFactoryBean userService(){ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();proxyFactoryBean.setTarget(new UserService());proxyFactoryBean.setInterceptorNames("methodInterceptor");return proxyFactoryBean;}}@Testpublic void springAOPTest1() {//因为UserService实现接口。所以产生JDK代理对象。只能使用接口类型ServiceInterface userService = (ServiceInterface) applicationContext.getBean("userService");userService.login();}
2.利用BeanNameAutoProxyCreator批量设置
需要手动设置切入点。
@Configurable@ComponentScan("com.masterlu.ioc.aop")public class AopDemoConfig {@Beanpublic MethodInterceptor methodInterceptor() {return new MethodInterceptor() {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("before");Object proceed = invocation.proceed();System.out.println("after");return proceed;}};}@Beanpublic 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 {//指定切入点以及增强逻辑。@Beanpublic DefaultPointcutAdvisor defaultPointcutAdvisor() {NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();pointcut.addMethodName("login");DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();defaultPointcutAdvisor.setPointcut(pointcut);defaultPointcutAdvisor.setAdvice(new MethodBeforeAdvice() {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {method.invoke(target, args);}});return defaultPointcutAdvisor;}// DefaultAdvisorAutoProxyCreator查找容器中所有Advisor实例@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();return defaultAdvisorAutoProxyCreator;}}
4.使用注解引入DefaultAdvisorAutoProxyCreator
@ComponentScan("com.masterlu")//DefaultAdvisorAutoProxyCreator查找容器中所有Advisor实例@Import(DefaultAdvisorAutoProxyCreator.class)public class AppConfig {//指定切入点以及增强逻辑。@Beanpublic DefaultPointcutAdvisor defaultPointcutAdvisor() {NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();pointcut.addMethodName("login");DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();defaultPointcutAdvisor.setPointcut(pointcut);defaultPointcutAdvisor.setAdvice(new MethodBeforeAdvice() {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {method.invoke(target, args);}});return defaultPointcutAdvisor;}}
DefaultPointcutAdvisor的功能可以使用注解(@Aspect、@Before、@After等注解)代替。
但是DefaultAdvisorAutoProxyCreator不能解析切面注解,需要使用AnnotationAwareAspectJAutoProxyCreator
5.利用注解设置注入点
@Component@Aspectpublic class DemoAspect {@Pointcut("execution(* *.login(..))")public void login() {}}
@ComponentScan("com.masterlu")@EnableAspectJAutoProxypublic class AppConfig {}
@EnableAspectJAutoProxy(本质引入AnnotationAwareAspectJAutoProxyCreator)
三、代码

