【小家Spring】面向切面编程Spring AOP创建代理的方式:ProxyFactoryBean、ProxyFactory、AspectJProxyFactory(JDK Proxy和CGLIB)(下)

简介: 【小家Spring】面向切面编程Spring AOP创建代理的方式:ProxyFactoryBean、ProxyFactory、AspectJProxyFactory(JDK Proxy和CGLIB)(下)

AspectJProxyFactory


其实ProxyFactory拥有的功能AspectjProxyFactory都有,它可以使用编程的方式去创建代理


在低版本Spring中定义一个切面是比较麻烦的,需要实现特定的接口,并进行一些较为复杂的配置,低版本Spring AOP的配置是被批评最多的地方。Spring听取这方面的批评声音,并下决心彻底改变这一现状。在Spring2.0中,Spring AOP已经焕然一新,你可以使用@AspectJ注解非常容易的定义一个切面,不需要实现任何的接口


AspectJ是目前大家最常用的 起到集成AspectJ和Spring,也就是我们平时长谈的:自动代理模式。它整个代理的过程全部交给Spring内部去完成,无侵入。


我们只需要配置切面、通知、切点表达式就能自动的实现切入的效果,使用起来极其方便,对调用者可以说是非常透明化的。相信这也是为何当下最流行这种方式的原因~


Demo体验

@Aspect
class MyAspect {
    @Pointcut("execution(* hello(..))")
    private void beforeAdd() {
    }
    @Before("beforeAdd()")
    public void before1() {
        System.out.println("-----------before-----------");
    }
}



在上述切面类定义中我们定义了一个Advisor(采用注解@Aspect标注的),其对应了一个MethodBeforeAdvice,实际上是一个AspectJMethodBeforeAdvice,该Advice对应的是上面的before1()方法,还对应了一个Pointcut:是一个AspectJExpressionPointcut。

该Advisor的语义拦截所有的方法名为**“hello”**的方法在它之前执行MyAspect.before1()方法。


如果我们现在需要创建一个代理对象,其需要绑定的Advisor逻辑跟上面定义的切面类中定义的Advisor类似。则我们可以进行如下编程:

    public static void main(String[] args) {
        AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new HelloServiceImpl());
    // 注意:此处得MyAspect类上面的@Aspect注解必不可少
        proxyFactory.addAspect(MyAspect.class);
        //proxyFactory.setProxyTargetClass(true);//是否需要使用CGLIB代理
        HelloService proxy = proxyFactory.getProxy();
        proxy.hello();
        System.out.println(proxy.getClass()); //class com.sun.proxy.$Proxy6
    }
输出:
-----------before-----------
this is my method~~
class com.sun.proxy.$Proxy6


这里面很有意思的地方在于:我们只是proxyFactory.addAspect(MyAspect.class);,就自动帮我们完成了方法、通知的绑定工作。


原理


public class AspectJProxyFactory extends ProxyCreatorSupport {
  /** Cache for singleton aspect instances */
  private static final Map<Class<?>, Object> aspectCache = new ConcurrentHashMap<>();
  //基于AspectJ时,创建Spring AOP的Advice  下面详说
  private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory();
  public AspectJProxyFactory() {
  }
  public AspectJProxyFactory(Object target) {
    Assert.notNull(target, "Target object must not be null");
    setInterfaces(ClassUtils.getAllInterfaces(target));
    setTarget(target);
  }
  public AspectJProxyFactory(Class<?>... interfaces) {
    setInterfaces(interfaces);
  }
  // 这两个addAspect方法是最重要的:我们可以把一个现有的aspectInstance传进去,当然也可以是一个Class(下面)======
  public void addAspect(Object aspectInstance) {
    Class<?> aspectClass = aspectInstance.getClass();
    String aspectName = aspectClass.getName();
    AspectMetadata am = createAspectMetadata(aspectClass, aspectName);
    // 显然这种直接传实例进来的,默认就是单例的。不是单例我们就报错了~~~~
    if (am.getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON) {
      throw new IllegalArgumentException(
          "Aspect class [" + aspectClass.getName() + "] does not define a singleton aspect");
    }
    // 这个方法就非常的关键了~~~ Singleton...是它MetadataAwareAspectInstanceFactory的子类
    addAdvisorsFromAspectInstanceFactory(
        new SingletonMetadataAwareAspectInstanceFactory(aspectInstance, aspectName));
  }
  public void addAspect(Class<?> aspectClass) {
    String aspectName = aspectClass.getName();
    AspectMetadata am = createAspectMetadata(aspectClass, aspectName);
    MetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName);
    addAdvisorsFromAspectInstanceFactory(instanceFactory);
  }
  // 从切面工厂里,把对应切面实例里面的增强器(通知)都获取到~~~
  private void addAdvisorsFromAspectInstanceFactory(MetadataAwareAspectInstanceFactory instanceFactory) {
    // 从切面工厂里,先拿到所有的增强器们~~~
    List<Advisor> advisors = this.aspectFactory.getAdvisors(instanceFactory);
    Class<?> targetClass = getTargetClass();
    Assert.state(targetClass != null, "Unresolvable target class");
    advisors = AopUtils.findAdvisorsThatCanApply(advisors, targetClass);
    AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors);
    AnnotationAwareOrderComparator.sort(advisors);
    addAdvisors(advisors);
  }
}



注意:


  • 需要注意的是在使用AspectjProxyFactory基于切面类创建代理对象时,我们指定的切面类上必须包含@Aspect注解。
  • 虽然我们自己通过编程的方式可以通过AspectjProxyFactory创建基于@Aspect标注的切面类的代理,但是通过配置<aop:aspectj-autoproxy/>(@EnableAspectJAutoProxy)使用基于注解的Aspectj风格的Aop时,Spring内部不是通过AspectjProxyFactory创建的代理对象,而是通过ProxyFactory(这个在分析自动代理源码的时候有说到过~~~~)


总结


这三个类本身没有什么关系,但都继承自:ProxyCreatorSupport,创建代理对象的核心逻辑都是在ProxyCreatorSupport中实现的


AspectJProxyFactory,ProxyFactoryBean,ProxyFactory 大体逻辑都是:


1.填充AdvisedSupport(ProxyCreatorSupport是其子类)的,然后交给父类ProxyCreatorSupport。


2.得到JDK或者CGLIB的AopProxy


3.代理调用时候被invoke或者intercept方法拦截 (分别在JdkDynamicAopProxy和ObjenesisCglibAopProxy(CglibAopProxy的子类)的中)

并且在这两个方法中调用ProxyCreatorSupport的getInterceptorsAndDynamicInterceptionAdvice方法去初始化advice和各个方法直接映射关系并缓存

相关文章
|
1月前
|
安全 Java 编译器
JDK 10中的局部变量类型推断:Java编程的简化与革新
JDK 10引入的局部变量类型推断通过`var`关键字简化了代码编写,提高了可读性。编译器根据初始化表达式自动推断变量类型,减少了冗长的类型声明。虽然带来了诸多优点,但也有一些限制,如只能用于局部变量声明,并需立即初始化。这一特性使Java更接近动态类型语言,增强了灵活性和易用性。
106 53
|
1月前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
21天前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
46 5
|
25天前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
52 8
|
25天前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
25天前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
36 5
|
25天前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
35 4
|
2月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
48 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
1月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
37 1
|
1月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
39 0
下一篇
DataWorks