Spring AOP 代理

Spring AOP 代理

1. Spring AOP 增强类型

AOP 联盟为通知 Advice 定义了 org.aopalliance.aop.Interface.Advice

Spring 按照通知 Advice 在目标类方法的连接点位置,可以分为 5 类

  • 前置通知:org.springframework.aop.MethodBeforeAdvice

    在目标方法执行前实施增强

  • 后置通知:ogr.springframework.aop.AfterReturningAdvice

    在目标方法执行后实施增强

  • 环绕通知:ogr.aopalliance.intercept.MethodInterceptor

    在目标方法执行前后实施增强

  • 异常抛出通知:org.springframework.aop.ThrowsAdvice

    在方法抛出异常后实施增强

  • 引介通知:org.springframework.aop.IntroductionInterceptor

    在目标类中添加一些新的方法和属性(Spring 中不支持,只支持对方法增强)


2. Spring AOP 切面类型

  • Advisor:代表一般切面,Advice 本身就是一个切面,对目标类所有方法进行拦截
  • PointcutAdvisor:代表具有切点的切面,可以指定拦截目标类哪些方法(实现时需要配置切面信息,即类中要增强的方法设置bean)
  • IntroductionAdvisor:代表引介切面,针对引介通知而使用切面(不要求掌握)

3. Advisor 切面案例 (xml 配置)

ProxyFactoryBean 常用可配置属性:

  • target:代理的目标对象
  • proxyInterfaces:代理要实现的接口

    如果多个接口可以使用以下格式赋值:

    <list>
      <value>xxx<value>
      ...
    </list>
  • proxyTargetClass:是否对类代理而不是接口,设置为 true 时,使用 CGLib 代理
  • interceptorNames:需要织入目标的 Advice
  • singleton:返回代理是否为单实例,默认为单例
  • optimize:当设置为 true 时,强制使用 CGLib(默认为 JDK 动态代理)

举个例子:

applicationContext.xml

<!-- 1. 配置目标类 -->
<bean id="studentDao" class="com.test.aop.demo3.StudentDaoImpl" />

<!-- 2. 前置通知类型 -->
<bean id="myBeforeAdvice" class="com.test.aop.demo3.MyBeforeAdvice" />

<!-- 3. Spring 的 AOP 产生代理对象 -->
<bean id="studentDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 配置目标类 -->
    <property name="target" ref="studentDao" />
    <!-- 实现的接口 -->
    <property name="proxyInterfaces" value="com.test.aop.demo3.StudentDao" />
    <!-- 采用拦截的名称 -->
    <!-- 注意这个地方使用 value -->
    <property name="interceptorNames" value="myBeforeAdvice" />
    <!-- 默认使用 jdk 动态代理,使用下列语句更改为 CGLib 生成代理 -->
    <property name="optimize" value="true" />
</bean>

通知类:

public class MyBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("前置增强========");
    }
}

4. 演示(Advisor 方式)

首先要使用 AOP,我们需要导入两个包:

<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.2.4.RELEASE</version>
</dependency>

然后定义接口和实现类,再定义一个通知类(如前置通知),然后我们在 xml 文件中配置目标类和通知类,利用 Spring AOP 产生代理(通过bean配置),具体可参考上述例子,使用注解的方式在测试类中导入增强后的 bean:studentDaoProxy。

具体代码:SpringDemo3.demo1()


5. PointcutAdvisor 切点切面

使用普通 Advice 作为切面,将对目标类所有方法进行拦截,不够灵活,在实际开发中常采用带有切点的切面。

常用 PointcutAdvisor 实现类

  • DefaultPointcutAdvisor 最常用的切面类型,它可以通过任意 PointcutAdvice 组合定义切面
  • JdkRegexpMethodPointcut 构造正则表达式切点

这里以 JdkRegexpMethodPointcut 为例:

applicationContext.xml

<!-- 配置目标类 -->
<bean id="customerDao" class="com.test.aop.demo4.CustomerDao" />

<!-- 配置通知 -->
<bean id="myAroundAdvice" class="com.test.aop.demo4.MyAroundAdvice" />

<!-- 一般的切面是使用通知作为切面的,因为要对目标类的某个方法进行增强就需要配置一个带有切入点的切面 -->
<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <!-- pattern 中配置正则表达式:. 任意字符 * 任意次数-->
    <!--<property name="pattern" value=".*save.*" />-->
    <property name="patterns" value=".*save.*,.*delete.*" />
    <property name="advice" ref="myAroundAdvice" />
</bean>

<!-- 配置产生代理 -->
<bean id="customerDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="customerDao" />
    <!-- 代表使用 CGLib 方法 -->
    <property name="proxyTargetClass" value="true" />
    <property name="interceptorNames" value="myAdvisor" />
</bean>

通知类:

public class MyAroundAdvice implements MethodInterceptor{

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("环绕前增强...");

        // 执行目标方法
        Object obj = methodInvocation.proceed();

        System.out.println("环绕后增强...");

        return obj;
    }
}

具体代码:SpringDemo4.demo1()


6. 自动创建代理

前面的案例中,每个代理都是通过 ProxyFactoryBean 织入切面代理,在实际开发中,非常多的 Bean 每个都配置 ProxyFactoryBean 开发维护量巨大。

解决方案:自动创建代理。

自动创建代理的三种方式:

  • BeanNameAutoProxyCreator 根据 Bean 名称创建代理
  • DefaultAdvisorAutoProxyCreator 根据 Advisor 本身包含信息创建代理
  • AnnotationAwareAspectJAutoProxyCreator 基于 Bean 中的 AspectJ 注解进行自动代理(最主要方式)

7. BeanNameAutoProxyCreator 举例

对所有以 Dao 结尾 Bean 所有方法使用代理:

<!-- 配置目标类 -->
<bean id="studentDao" class="com.test.aop.demo5.StudentDaoImpl" />
<bean id="customerDao" class="com.test.aop.demo5.CustomerDao" />

<!-- 配置增强 -->
<bean id="myAroundAdvice" class="com.test.aop.demo5.MyAroundAdvice" />
<bean id="myBeforeAdvice" class="com.test.aop.demo5.MyBeforeAdvice" />

<!-- 自动创建代理不需要 id -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames" value="*Dao" />
    <property name="interceptorNames" value="myBeforeAdvice" />
</bean>

具体代码:SpringDemo5.demo1()


8. DefaultAdvisorAutoProxyCreator 举例

配置环绕代理案例:

<!-- 配置目标类 -->
<bean id="studentDao" class="com.test.aop.demo6.StudentDaoImpl" />
<bean id="customerDao" class="com.test.aop.demo6.CustomerDao" />

<!-- 配置增强 -->
<bean id="myAroundAdvice" class="com.test.aop.demo6.MyAroundAdvice" />
<bean id="myBeforeAdvice" class="com.test.aop.demo6.MyBeforeAdvice" />

<!-- 配置切面 -->
<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="pattern" value="com\.test\.aop\.demo6\.CustomerDao\.save" />
    <property name="advice" ref="myAroundAdvice" />
</bean>

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />

具体代码:SpringDemo6.demo1()

原文地址:https://www.cnblogs.com/weixuqin/p/11061370.html

时间: 2024-08-27 07:20:10

Spring AOP 代理的相关文章

jdk动态代理与cglib代理、spring aop代理实现原理解析

原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 动态代理实现主要有2种形式,主要分为: 1.jdk动态代理: 1)原理:是根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口 面向接口生成代理,位于java.lang.reflect包下) 2)实现方式: 1. 通过实现Invocati

spring AOP 代理(静态与动态)

一.没有代理模式 缺点: 1.工作量特别大,如果项目中有多个类,多个方法,则要修改多次. 2.违背了设计原则:开闭原则(OCP),对扩展开放,对修改关闭,而为了增加功能把每个方法都修改了,也不便于维护. 3.违背了设计原则:单一职责(SRP),每个方法除了要完成自己本身的功能,还要计算耗时.延时:每一个方法引起它变化的原因就有多种. 4.违背了设计原则:依赖倒转(DIP),抽象不应该依赖细节,两者都应该依赖抽象.而在Test类中,Test与Math都是细节. 假设需实现一个计算的类Math.完成

Spring AOP 实现原理(三) 使用 使用 CGLIB 生成代理类

CGLIB(Code Generation Library),简单来说,就是一个代码生成类库.它可以在运行时候动态是生成某个类的子类. 此处使用前面定义的 Chinese 类,现在改为直接使用 CGLIB 来生成代理,这个代理类同样可以实现 Spring AOP 代理所达到的效果. 下面先为 CGLIB 提供一个拦截器实现类: public class AroundAdvice implements MethodInterceptor { public Object intercept(Obje

spring aop 原理

http://blog.csdn.net/moreevan/article/details/11977115 Spring AOP 实现原理 2013-09-24 15:23 79554人阅读 评论(11) 收藏 举报  分类: spring(2)  版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)

java框架篇---spring AOP 实现原理

什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无

Spring AOP 实现原理

什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无

Spring AOP深入理解之拦截器调用

Spring AOP深入理解之拦截器调用 Spring AOP代理对象生成回想 上一篇博客中:深入理解Spring AOP之二代理对象生成介绍了Spring代理对象是怎样生成的,当中重点介绍了JDK动态代理方式,简单回想下代理对象生成过程: 1.上面讲到了两种生成代理对象的方法,一种是通过ProxyFactory,一种是通过ProxyFactoryBean. 第一种获取比較简单,可是须要手工的进行写代码.而另外一种是通过Spring的IOC机制来控制Bean的生成. 2.不管是ProxyFact

“AOP代理”遇到“双上下文”

最近有小伙伴儿遇到了一个问题来咨询我,问题大致如下: 他在Service层利用Aspect设置了一个Spring AOP代理,在单元测试以及在service层代码上添加代理的时候均没有发现问题,但是在web服务中的controller层代码添加代理的时候却不成功. 其代码大概如下: @Component public class CoreBusiness { public void doSomething() { System.out.println("I did something"

Spring AOP的本质

不用再百科什么AOP了,我先推荐几篇文章或者系列文章:(感谢这些博文的原作者) 0.  Spring AOP 详解   http://pandonix.iteye.com/blog/336873/ 1.  AOP技术基础系列     http://wayfarer.cnblogs.com/articles/241024.html 2.  我对AOP的理解 http://jinnianshilongnian.iteye.com/blog/1474325 3.  Spring AOP本质系列  ht