Spring中的AOP
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring中的AOP相关的知识,希望对你有一定的参考价值。
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已经是代理对象.
以上是关于Spring中的AOP的主要内容,如果未能解决你的问题,请参考以下文章