Spring中的AOP(8)

Spring的传统AOP

AOP:不是由Spring定义.AOP联盟的组织定义.
Spring中的通知:(增强代码)

  • 前置通知 org.springframework.aop.MethodBeforeAdvice
    * 在目标方法执行前实施增强
  • 后置通知 org.springframework.aop.AfterReturningAdvice
    * 在目标方法执行后实施增强
  • 环绕通知 org.aopalliance.intercept.MethodInterceptor
    * 在目标方法执行前后实施增强
  • 异常抛出通知 org.springframework.aop.ThrowsAdvice
    * 在方法抛出异常后实施增强
  • 引介通知 org.springframework.aop.IntroductionInterceptor(课程不讲.)
    * 在目标类中添加一些新的方法和属性

Spring中的切面类型

  • Advisor : Spring中传统切面.
    * Advisor:都是有一个切点和一个通知组合.
    * Aspect:多个切点和多个通知组合.
  • Advisor : 代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截(* 不带有切点的切面.针对所有方法进行拦截)
  • PointcutAdvisor : 代表具有切点的切面,可以指定拦截目标类哪些方法(带有切点的切面,针对某个方法进行拦截)
  • IntroductionAdvisor : 代表引介切面,针对引介通知而使用切面(不要求掌握)

Spring的AOP的开发

针对所有方法的增强:(不带有切点的切面)

  • 第一步:导入相应jar包.
    * spring-aop-3.2.0.RELEASE.jar
    * com.springsource.org.aopalliance-1.0.0.jar
  • 第二步:编写被代理对象:
    * CustomerDao接口
package cn.spring3.demo3;
/*接口类
*/
public interface CustomerDao {
    public void add();
    public void update();
    public void delete();
    public void find();
}

* CustoemrDaoImpl实现类

package cn.spring3.demo3;

/**
 * @author NOP
 * 针对所有方法的增强
 */
public class CustomerDaoImpl implements CustomerDao {
    public void add() {
        System.out.println("添加客户");
    }
    public void delete() {
        System.out.println("删除客户");
    }
    public void find() {
        System.out.println("查询客户");
    }
    public void update() {
        System.out.println("修改客户");
    }
}
  • 第三步:编写增强的代码:
package cn.spring3.demo3;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
 * @author NOP
 * 前置增强
 */
public class MyBeforeAdvice implements MethodBeforeAdvice{
    /**
     * method:执行的方法
     * args:参数
     * target:目标对象
     */
    public void before(Method method, Object[] args, Object target)
            throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("前置增强...");
    }
}
  • 第四步:生成代理:(配置生成代理:)

* 生成代理Spring基于ProxyFactoryBean类.底层自动选择使用JDK的动态代理还是CGLIB的代理.
* 属性:
target : 代理的目标对象
proxyInterfaces : 代理要实现的接口
如果多个接口可以使用以下格式赋值
<list>
<value></value>
....
</list>
proxyTargetClass : 是否对类代理而不是接口,设置为true时,使用CGLib代理
interceptorNames : 需要织入目标的Advice
singleton : 返回代理是否为单实例,默认为单例
optimize : 当设置为true时,强制使用CGLib

<!-- 传统方式代理 -->
    <!-- 不带有切点的切面 -->
    <!-- 目标对象 -->
    <bean id="customerDao" class="cn.spring3.demo3.CustomerDaoImpl"></bean>

    <!-- 定义增强 -->
    <bean id="beforeAdvice" class="cn.spring3.demo3.MyBeforeAdvice"></bean>

    <!-- Srping配置增强代理 -->
    <bean id="customerDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 设置目标对象 -->
        <property name="target" ref="customerDao"></property>
        <!-- 设置实现的接口 ,value中写接口的全路径-->
        <property name="proxyInterfaces" value="cn.spring3.demo3.CustomerDao"></property>
        <!-- 需要使用的value:要的名称 -->
        <property name="interceptorNames" value="beforeAdvice"></property>
        <!-- 强制使用CGLib代理
        <property name="optimize" value="true"/>
        -->
    </bean>
    <!-- 不带有切点的切面 -->

第五步:编写测试类

package cn.spring3.demo3;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest3 {

    @Autowired
    //@Qualifier("customerDao")//注入的真实的对象,必须注入代理对象
    @Qualifier("customerDaoProxy")
    private CustomerDao customerDao;
    /*
     * 不带有切点的切面
     */
    @Test
    public void demo1(){
        customerDao.add();
        customerDao.delete();
        customerDao.find();
        customerDao.update();
    }
}
测试结果:
前置增强...
添加客户
前置增强...
删除客户
前置增强...
查询客户
前置增强...
修改客户

带有切点的切面:(针对目标对象的某些方法进行增强)

  • PointcutAdvisor 接口:

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

第一步:创建被代理对象.
* OrderDao

package cn.spring3.demo4;
/**
 * @author NOP
 * 目标对象
 */
public class OrderDao {
    public void add() {
        // TODO Auto-generated method stub
        System.out.println("添加订单");
    }
    public void delete() {
        // TODO Auto-generated method stub
        System.out.println("删除订单");
    }
    public void find() {
        // TODO Auto-generated method stub
        System.out.println("查询订单");
    }
    public void update() {
        // TODO Auto-generated method stub
        System.out.println("修改订单");
    }
}

第二步:编写增强的类:

package cn.spring3.demo4;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
 * @author NOP 增强的类 使用的是环绕
 */
public class MyAroundAdvice implements MethodInterceptor {
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("环绕前增强。。。");
        Object result = methodInvocation.proceed();// 执行目标对象的方法
        System.out.println("环绕后增强。。。");
        return result;
    }
}

第三步:生成代理:

<!-- 带有切点的切面 -->
    <!-- 目标对象 -->
    <bean id="orderDao" class="cn.spring3.demo4.OrderDao"></bean>
    <!-- 定义增强 -->
    <bean id="aroundAdvice" class="cn.spring3.demo4.MyAroundAdvice"></bean>
    <!-- ********************************定义切点*************** -->
    <bean id="mypointcutAdviesor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!--定义正则表达式,规定哪些方法执行拦截  pattern是一个方法patterns是多个方法-->
        <!-- <property name="pattern" value=".*"/> 这个正则是所有-->
        <!--<property name="pattern" value="cn\.spring3\.demo4\.OrderDao\.delete.*"/>-->
        <!--<property name="pattern" value=".*add.*"/>-->
        <property name="patterns" value=".*add.*,.*update.*"/>
        <!-- 应用增强 -->
        <property name="advice" ref="aroundAdvice"/>
    </bean>
    <!-- ********************************定义切点*************** -->
    <!-- 定义生成代理对象 -->
    <bean id="orderDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 设置目标对象 -->
        <property name="target" ref="orderDao"></property>
        <!-- 针对类的代理-->
        <property name="proxyTargetClass" value="true"></property>
        <!-- 在目标上应用增强 -->
        <property name="interceptorNames" value="mypointcutAdviesor"></property>
    </bean>
    <!-- 带有切点的切面 -->

第四步:编写测试类

package cn.spring3.demo4;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTest1 {
    @Autowired
    //@Qualifier("orderDao")//注入的真实的对象,必须注入代理对象
    @Qualifier("orderDaoProxy")
    private OrderDao orderDao;
    /*
     * 带有切点的切面
     */
    @Test
    public void demo1(){
        orderDao.add();
        orderDao.delete();
        orderDao.find();
        orderDao.update();
    }
}
测试结果:
环绕前增强。。。
添加订单
环绕后增强。。。
删除订单
查询订单
环绕前增强。。。
修改订单
环绕后增强。。。

自动代理

  • 前面的案例中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大
  • 自动创建代理(*****基于后处理Bean.在Bean创建的过程中完成的增强.生成Bean就是代理.)
  • BeanNameAutoProxyCreator 根据Bean名称创建代理
  • DefaultAdvisorAutoProxyCreator 根据Advisor本身包含信息创建代理
    • * AnnotationAwareAspectJAutoProxyCreator 基于Bean中的AspectJ 注解进行自动代理

自动方式代理没有切点切面的增强

<!-- 自动方式代理没有切点切面的增强 -->
    <!-- 目标对象 -->
    <bean id="customerDao" class="cn.spring3.demo3.CustomerDaoImpl"></bean>
    <bean id="orderDao" class="cn.spring3.demo4.OrderDao"></bean>

    <!-- 定义增强 -->
    <bean id="beforeAdvice" class="cn.spring3.demo3.MyBeforeAdvice"></bean>
    <bean id="aroundAdvice" class="cn.spring3.demo4.MyAroundAdvice"></bean>

    <!-- 自动代理:按名称的代理 基于后处理Bean,后处理Bean不需要配置ID -->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="*Dao"/>
        <property name="interceptorNames" value="beforeAdvice"/>
    </bean>

编写测试类:

package cn.spring3.demo5;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import cn.spring3.demo3.CustomerDao;
import cn.spring3.demo4.OrderDao;

/**
 * @author NOP
 * 自动方式代理没有切点切面的增强
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class SpringTest {
    @Autowired
    @Qualifier("orderDao")//不用注入代理,因为类已经是代理了
    private OrderDao orderDao;
    @Autowired
    @Qualifier("customerDao")
    private CustomerDao customerDao;

    @Test
    public void demo1(){
        orderDao.add();
        orderDao.delete();
        customerDao.find();
        customerDao.update();
    }
}
测试结果:
前置增强...
添加订单
前置增强...
删除订单
前置增强...
查询客户
前置增强...
修改客户

自动方式代理 有切点切面的增强

<!-- 自动方式代理 有切点切面的增强 -->
    <!-- 目标对象 -->
    <bean id="customerDao" class="cn.spring3.demo3.CustomerDaoImpl"></bean>
    <bean id="orderDao" class="cn.spring3.demo4.OrderDao"></bean>

    <!-- 定义增强 -->
    <bean id="beforeAdvice" class="cn.spring3.demo3.MyBeforeAdvice"></bean>
    <bean id="aroundAdvice" class="cn.spring3.demo4.MyAroundAdvice"></bean>

    <!-- 定义切点 -->
    <bean id="mypointcutAdviesor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!--定义正则表达式,规定哪些方法执行拦截  -->
        <property name="patterns" value=".*add.*,.*update.*"/>
        <!-- 应用增强 -->
        <property name="advice" ref="beforeAdvice"/>
    </bean>

    <!-- 自动代理:按名称的代理 基于后处理Bean,后处理Bean不需要配置ID -->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="*Dao"/>
        <property name="interceptorNames" value="mypointcutAdviesor"/>
    </bean>

编写测试类:

package cn.spring3.demo5;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import cn.spring3.demo3.CustomerDao;
import cn.spring3.demo4.OrderDao;

/**
 * @author NOP
 * 自动方式代理 有切点切面的增强
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class SpringTest_1 {
    @Autowired
    @Qualifier("orderDao")
    private OrderDao orderDao;
    @Autowired
    @Qualifier("customerDao")
    private CustomerDao customerDao;

    @Test
    public void demo1(){
        orderDao.add();
        orderDao.delete();
        orderDao.update();
        orderDao.find();

        customerDao.add();
        customerDao.delete();
        customerDao.update();
        customerDao.find();
    }
}
测试结果:
前置增强...
添加订单
删除订单
前置增强...
修改订单
查询订单
前置增强...
添加客户
删除客户
前置增强...
修改客户
查询客户

区分基于ProxyFactoryBean的代理与自动代理区别?
***** ProxyFactoryBean:先有被代理对象,将被代理对象传入到代理类中生成代理.
自动代理基于后处理Bean.在Bean的生成过程中,就产生了代理对象,把代理对象返回.生成Bean已经是代理对象.

原文地址:http://blog.51cto.com/4534309/2112427

时间: 2024-11-08 23:35:35

Spring中的AOP(8)的相关文章

spring中的aop注解(整合junit测试)

使用spring中的aop前先来了解一下spring中aop中的一些名词 Joimpoint(连接点):目标对象中,所有可能增强的方法 PointCut(切入点):目标对象,已经增强的方法 Advice(通知/增强):增强的代码 Target(目标对象):被代理对象 Weaving(织入):将通知应用到切入点的过程 Proxy(代理):将通知织入到目标对象之后,形成代理对象 aspect(切面):切入点+通知 一:不使用spring的aop注解 以javaEE中的service层为例 UserS

Spring中的AOP(五)——在Advice方法中获取目标方法的参数

摘要: 本文介绍使用Spring AOP编程中,在增强处理方法中获取目标方法的参数,定义切点表达式时使用args来快速获取目标方法的参数. 获取目标方法的信息 访问目标方法最简单的做法是定义增强处理方法时,将第一个参数定义为JoinPoint类型,当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点.JoinPoint里包含了如下几个常用的方法: Object[] getArgs:返回目标方法的参数 Signature getSignature:返回目标方法的签名 Ob

深入分析JavaWeb Item54 -- Spring中的AOP面向切面编程2

一.在Advice方法中获取目标方法的参数 1.获取目标方法的信息 访问目标方法最简单的做法是定义增强处理方法时,将第一个参数定义为JoinPoint类型,当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点.JoinPoint里包含了如下几个常用的方法: Object[] getArgs:返回目标方法的参数 Signature getSignature:返回目标方法的签名 Object getTarget:返回被织入增强处理的目标对象 Object getThis:返

Spring中的AOP

在上一篇博客中,我们讲了Spring的IOC,以下,我们继续解说Spring的还有一个核心AOP AOP: 在软件业,AOP为Aspect Oriented Programming的缩写.意为:面向切面编程,通过预编译方式和执行期动态代理实现程序功能的统一维护的一种技术. AOP也是Action Oriented Programming 的缩写,意为:面向切面编程,是函数式编程的一种衍生范型.AOP在其它领域也有其它含义. AOP的具体解释: 还是老规矩,站在巨人的肩膀上,看看其它人对AOP的理

spring中的AOP 以及各种通知

理解了前面动态代理对象的原理之后,其实还是有很多不足之处,因为如果在项目中有20多个类,每个类有100多个方法都需要判断是不是要开事务,那么方法调用那里会相当麻烦. spring中的AOP很好地解决了这个问题,通过 execution表达式 指定哪些包中的那些类 哪些方法 用到事务 execution(public * *(..))  所有的公共方法 execution(* set*(..))  以set开头的任意方法 execution(* com.xyz.service.AccountSer

Java——面向切面编程,Spring中的AOP编程

面向切面编程 AOP思想:将横向重复代码,纵向抽取出来 AOP体现--Filter AOP体现--拦截器 AOP体现--动态代理 Spring中实现AOP思想 原理:Spring可以为容器中管理的对象生成代理对象 代理分为动态代理和cglib代理: 动态代理(优先) 被代理对象必须要实现接口,才能产生代理对象,如果没有接口将不能使用动态代理技术,换句话说,就是代理对象和被代理要实现同一接口 cglib代理 第三方代理技术,cglib代理,可以对任何类生成代理,代理的原理是对目标对象进行继承代理,

2018.12.24 Spring中的aop演示

Aop的最大意义是:在不改变原来代码的前提下,也不对源代码做任何协议接口要求.而实现了类似插件的方式,来修改源代码,给源代码插入新的执行代码. 4.spring中的aop演示 4.1步骤: 1.导包(4+2+2+2+1) 基础包+日志包+aop.aspects+test+weaver+aopalliance 下面两个是spring需要的第三方aop包 com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar com.springsource.or

Spring中的AOP注解方式和配置方式

今天学习了下spring中的切面编程:结合之前看过的视频.整合一下思路: 基本类: 接口: public interface ArithmeticCalculator { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); } 接口的实现: import org.springframework.stereotype.Component; @Component("ar

Spring(二) Spring中的AOP和属性注入

一.AOP(Aspect Oriented Programing)面向切面编程 AOP的终极目标:让我们可以专心做事 下面通过一个例子来介绍AOP的具体使用 案例的要求:使用AOP实现日志记录系统 ,  核心模块  和    增强  单独  开发  ,运行时再组装 首先定义接口和方法 接口和实现类中的代码,我放在一起了,应该比较简单 package demo04.dao; /** * Created by mycom on 2018/3/5. */ public interface IHello