spring之AOP源码分析上

目录

动态代理

cglib动态代理

jdk动态代理

ProxyFactory

Advice的分类

Advisor的理解

spring创建代理对象的方式

ProxyFactoryBean(相对灵活,可以更精细地控制代理对象的创建过程)

BeanNameAutoProxyCreator(适合对特定Bean进行简单代理的场景)

DefaultAdvisorAutoProxyCreator(适合使用切面(Aspect)来定义通知的情况)


动态代理

       aop其实就是动态代理的一种体现,像spring的事务也是一种动态代理的体现。比如我们对某个方法进行增强,其实就是通过动态代理的方式在执行某个方法之前,进行方法前或者方法后等一些操作,比如比较常见的用@Before("execution(代理逻辑)")来记录操作日志等。

       动态代理又分为两种,一种是cglib,一种是jdk。

cglib动态代理
public class UserService  {

  public void test() {

     System.out.println("test...");

  }
}
//此时,我们new一个UserService对象,然后执行test()方法,结果是显而易见的。
-----------------------------------------------------------------------------------------
//如果我们现在想在不修改UserService类的源码前提下,给test()增加额外逻辑,
//那么就可以使用动态代理机制来创建UserService对象了,比如:
UserService target = new UserService();

// 通过cglib技术
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);

// 定义额外逻辑,也就是代理逻辑
enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
 @Override
 public Object intercept(Object o, Method method, Object[] objects, MethodProxy
 methodProxy) throws Throwable {
  System.out.println("before...");
  Object result = methodProxy.invoke(target, objects);
  System.out.println("after...");
  return result;
 }
}});

// 动态代理所创建出来的UserService对象
UserService userService = (UserService) enhancer.create();

// 执行这个userService的test方法时,就会额外会执行一些其他逻辑
userService.test();

       得到的都是UserService对象,但是执行test()方法时的效果却不一样了,这就是代理所带来的效果。

       上面是通过cglib来实现的代理对象的创建,是基于父子类的,被代理类(UserService)是父类,代理类是子类,代理对象就是代理类的实例对象,代理类是由cglib创建的,对于程序员来说不用关心。

jdk动态代理

注意:jdk动态代理只能代理实现接口,也就是一个类需要先实现接口才能利用jdk动态代理来生成代理对象。

public interface UserInterface {

   public void test();

}

public class UserService implements UserInterface {

 public void test() {

    System.out.println("test...");

  }
}
//创建将要使用jdk动态代理的UserService类

------------------------------------------------------------------------------------------

//利用JDK动态代理来生成一个代理对象

UserService target = new UserService();

// UserInterface接口的代理对象
Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(), 
new Class[]{UserInterface.class}, new InvocationHandler() {
     @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("before...");
      Object result = method.invoke(target, args);
      System.out.println("after...");
      return result;
     }
});

UserInterface userService = (UserInterface) proxy;
userService.test();

       如果将new Class[]{UserInterface.class},替换成new Class[]{UserService.class},代码会直接报错,表示一定要是个接口。


ProxyFactory

        上述两种动态代理技术,在spring中已经进行了封装ProxyFactory,表示创建代理对象的工厂,使用更加方便。

UserService target = new UserService();

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(new MethodInterceptor() {
 @Override
 public Object invoke(MethodInvocation invocation) throws Throwable {
  System.out.println("before...");
  Object result = invocation.proceed();
  System.out.println("after...");
  return result;
 }
});

UserInterface userService = (UserInterface) proxyFactory.getProxy();
userService.test();

ProxyFactory会自动去判断使用那种动态代理,如果没有实现接口就用cglib,反之亦然。

Advice的分类

  1. 前置通知(Before Advice): 在目标方法执行前执行的通知。
  2. 后置通知(After Advice): 在目标方法执行后执行的通知。
  3. 返回通知(After Returning Advice): 在目标方法正常返回结果后执行的通知。
  4. 异常通知(After Throwing Advice): 在目标方法抛出异常后执行的通知。
  5. 环绕通知(Around Advice): 包围目标方法的通知,在目标方法执行前后都执行,并控制目标方法的执行过程。

Advisor的理解

   Advisor 是一个包含了切面的全部信息的对象,它将AdvicePointcut(切入点)结合起来。Pointcut 定义了在什么地方(连接点)应用切面逻辑,而 Advice 定义了切面实际执行的逻辑。

        Spring中常见的实现Advisor接口的类是 DefaultPointcutAdvisor,它通过组合 Pointcut 和 Advice 来创建一个完整的切面。Pointcut 用于匹配连接点,而 Advice 则定义了在匹配的连接点上执行的逻辑。

spring创建代理对象的方式

        在使用Spring时,并不会直接去使用ProxyFactory。

ProxyFactoryBean(相对灵活,可以更精细地控制代理对象的创建过程)
@Bean
public ProxyFactoryBean userServiceProxy(){
 UserService userService = new UserService();

 ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
 proxyFactoryBean.setTarget(userService);
 proxyFactoryBean.addAdvice(new MethodInterceptor() {
  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
   System.out.println("before...");
   Object result = invocation.proceed();
   System.out.println("after...");
   return result;
  }
 });
 return proxyFactoryBean;
}

       这种方式定义的Bean是经过AOP的,只能针对某一个Bean,定制化相当于FactoryBean,并将代理对象生成了Bean。

       ProxyFactoryBean还有额外的功能,比如把某个Advise或Advisor定义成为Bean,然后在ProxyFactoryBean中进行设置

@Bean
public MethodInterceptor AroundAdvise(){
 return new MethodInterceptor() {
  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
   System.out.println("before...");
   Object result = invocation.proceed();
   System.out.println("after...");
   return result;
  }
 };
}

@Bean
public ProxyFactoryBean userService(){
    UserService userService = new UserService();
    ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
    proxyFactoryBean.setTarget(userService);
    proxyFactoryBean.setInterceptorNames("AroundAdvise");
    return proxyFactoryBean;
}
BeanNameAutoProxyCreator(适合对特定Bean进行简单代理的场景)

BeanNameAutoProxyCreator通过指定某个bean的名字,来对该bean进行代理

@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
     BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
     //表示可批量对Bean进行AOP
     beanNameAutoProxyCreator.setBeanNames("userSe*");
     beanNameAutoProxyCreator.setInterceptorNames("AroundAdvise");
     beanNameAutoProxyCreator.setProxyTargetClass(true);
     return beanNameAutoProxyCreator;
}

       指定了一个InterceptorName,也就是一个Advise,前提条件是这个Advise也得是一个Bean,这样Spring才能找到的。BeanNameAutoProxyCreator的缺点是只能根据beanName来指定想要代理的Bean。

DefaultAdvisorAutoProxyCreator(适合使用切面(Aspect)来定义通知的情况)

       此方式就是我们编写一个切面类,里边包含切面方法,像@Befoer、@After等,通过扫描Spring容器中的Advisor,为匹配的Bean创建代理对象,并将Advisor中定义的通知应用到代理对象上。

@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor(){
    NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
    pointcut.addMethodName("test");
    DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
    defaultPointcutAdvisor.setPointcut(pointcut);
    defaultPointcutAdvisor.setAdvice(new XXXAfterReturningAdvise());
    return defaultPointcutAdvisor;
}

@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new 
    DefaultAdvisorAutoProxyCreator();
    return defaultAdvisorAutoProxyCreator;
}

        上述方式为非注解方式,注解方式就是@Before、@After,如果是注解方式会通过@EnableAspectJAutoProxy注解去解析,后续会分析。

你可能感兴趣的:(spring源码,spring,java,后端)