2017-11-10 17:25:48

Spring中通知Advice类型(增强代码):

  • 前置通知,org.springframework.aop.MethodBeforeAdvice:方法前
  • 后置通知,org.springframework.aop.AfterReturningAdvice:方法后
  • 环绕通知,org.aopalliance.intercept.MethodInterceptor:方法前后
  • 异常抛出通知,org.springframework.aop.ThrowsAdvice:异常抛出后的增强
  • 引介通知,org.springframework.aop.IntroductionInterceptor:类的增强

Spring中切面的类型:

  • Advisor:AOP中的传统切面,Advice本身就是一个切面,对所有方法进行增强 -- 也被称为不带切点的切面
  • PointcutAdvisor:针对某些方法进行增强 -- 也被称为带有切点的切面
  • IntroductionAdvisor:代表引介的切面,针对类的切面

Spring中AOP开发的几个步骤:

  • 第一步:导入相应jar包.
    * spring-aop-3.2.0.RELEASE.jar
    * com.springsource.org.aopalliance-1.0.0.jar
  • 第二步:编写被代理对象
  • 第三步:编写增强的代码,编写具体类来实现前置增强,后置增强以及环绕增强
  • 第四步:配置生成代理

 一、不带切点的切面:Advisor

// 接口
public interface Person {
public void add();
public void delete();
} // 实现类
public class PersonImpl implements Person {
@Override
public void add() {
System.out.println("添加方法...");
} @Override
public void delete() {
System.out.println("删除方法...");
}
} // 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-config.xml")
public class Demo {
@Resource(name = "proxy")
private Person p; @Test
public void fun(){
p.add();
}
}

通过xml进行配置代理:

生成代理Spring基于ProxyFactoryBean类,底层自动选择使用JDK的动态代理还是CGLIB的代理.
属性:

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

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

<list>
<value></value>
....
</list>

  • proxyTargetClass : 是否对类代理而不是接口,设置为true时,使用CGLib代理
  • interceptorNames : 需要织入目标的Advice
  • singleton : 返回代理是否为单实例,默认为单例
  • optimize : 当设置为true时,强制使用CGLib
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--定义目标对象-->
<bean id="person" class="spring1.PersonImpl"/>
<!--定义增强-->
<bean id="before" class="spring1.MethodBef"/> <!--Spring支持配置生成代理-->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 设置目标对象 -->
<property name="target" ref="person"/>
<!-- 设置实现的接口 ,value中写接口的全路径 -->
<property name="proxyInterfaces" value="spring1.Person"/>
<!-- 需要使用的切面,这里增强即是切面-->
<property name="interceptorNames" value="before"/>
</bean>
</beans>

注意:

  • 使用注解的时候不仅需要导入Junit4.12,还需要导入hamcrest-core
  • 在使用接口方式生成代理的时候,返回的类的类型必须是接口类型。
  • 这种方法有两个弊端,一是每个类都需要手动进行代理的配置,显得比较麻烦;二是由于是不带切点的,导致灵活性变差,所以并不常用。

二、带有切点的切面:PointcutAdvisor

PointcutAdvisor接口有三种实现:DefaultPointcutAdvisor , RegexpMethodPointcutAdvisor 和 NameMatchMethodPointcutAdvisor,它们都在org.springframework.aop.support包中。

  • RegexpMethodPointcutAdvisor是通过正则表达式来匹配拦截的方法
  • NameMatchMethodPointcutAdvisor通过直接指定那些方法是需要拦截的,它也可以用*作为通配符
  • DefaultPointcutAdvisor则需要自定义切入点类
// 具体类
public class PersonImpl implements Person {
@Override
public void add() {
System.out.println("添加方法...");
} @Override
public void delete() {
System.out.println("删除方法...");
}
} // 自定义增强
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; public class AroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("环绕前增强..."); // 执行目标对象的方法
Object res = methodInvocation.proceed(); System.out.println("环绕后增强..."); return res;
}
} // 测试
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-config.xml")
public class Demo {
@Resource(name = "proxy2")
private Person p; @Test
public void fun(){
p.add();
}
}

通过配置来生成代理:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--定义目标对象-->
<bean id="person" class="spring1.PersonImpl"/>
<!--定义增强-->
<bean id="before" class="spring1.MethodBef"/>
<bean id="around" class="spring1.AroundAdvice"/> <!--Spring支持配置生成代理-->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 设置目标对象 -->
<property name="target" ref="person"/>
<!-- 设置实现的接口 ,value中写接口的全路径 -->
<property name="proxyInterfaces" value="spring1.Person"/>
<!-- 需要使用的增强 -->
<property name="interceptorNames" value="before"/>
</bean> <!--定义带有切点的切面代理--> <!--定义切点切面-->
<bean id="mypointcut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!--定义正则表达式,来限定切点-->
<property name="pattern" value=".*"/>
<!--添加增强-->
<property name="advice" ref="around"/>
</bean> <bean id="proxy2" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 设置目标对象 -->
<property name="target" ref="person"/>
<!-- 设置实现的接口 ,value中写接口的全路径 -->
<property name="proxyInterfaces" value="spring1.Person"/>
<!-- 需要使用的增强 -->
<property name="interceptorNames" value="mypointcut"/>
</bean>
</beans>

三、自动代理

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

自动创建代理(基于后处理Bean,在Bean创建的过程中完成的增强,生成Bean就是代理 .)

  • BeanNameAutoProxyCreator :根据Bean名称创建代理
  • DefaultAdvisorAutoProxyCreator :根据Advisor本身包含信息创建代理
  • AnnotationAwareAspectJAutoProxyCreator :基于Bean中的AspectJ 注解进行自动代理

基于后处理Bean的都不用配置id。

* BeanNameAutoProxyCreator: 按名称生成代理

// 实现类
public class PersonImpl implements Person {
@Override
public void add() {
System.out.println("添加方法...");
} @Override
public void delete() {
System.out.println("删除方法...");
}
} //增强
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; public class AroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("环绕前增强..."); // 执行目标对象的方法
Object res = methodInvocation.proceed(); System.out.println("环绕后增强..."); return res;
}
} public class MethodBef implements MethodBeforeAdvice{
/**
* method:执行的方法
* args:参数
* o:目标对象
*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("前置增强...");
}
} // 测试
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:config.xml")
public class Demo {
// 这里直接使用person进行注入就可以了
@Resource(name = "person")
private Person p; @Test
public void fun(){
p.add();
}
}

使用XML进行配置(如果想对特定方法,只需要配置一个有切点的切面就可以了):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--定义目标对象-->
<bean id="person" class="spring1.PersonImpl"/>
<!--定义增强-->
<bean id="before" class="spring1.MethodBef"/>
<bean id="around" class="spring1.AroundAdvice"/> <!-- 自动代理:按名称的代理,基于后处理Bean,后处理Bean,不需要配置id-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!--设置需要代理的beanname,支持正则-->
<property name="beanNames" value="person"/>
<property name="interceptorNames" value="around"/>
</bean> </beans>

* DefaultAdvisorAutoProxyCreator:根据切面中定义的信息生成代理

// 实现类
public class PersonImpl implements Person {
@Override
public void add() {
System.out.println("添加方法...");
} @Override
public void delete() {
System.out.println("删除方法...");
}
} // 增强
public class AroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("环绕前增强..."); // 执行目标对象的方法
Object res = methodInvocation.proceed(); System.out.println("环绕后增强..."); return res;
}
} // 测试
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:config2.xml")
public class Demo {
// 这里直接使用person进行注入就可以了
@Resource(name = "person")
private Person p; @Test
public void fun(){
p.add();
p.delete();
}
}

使用配置进行自动代理:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--定义目标对象-->
<bean id="person" class="spring1.PersonImpl"/>
<!--定义增强-->
<bean id="before" class="spring1.MethodBef"/>
<bean id="around" class="spring1.AroundAdvice"/> <!-- 定义一个带有切点的切面 -->
<bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="pattern" value=".*add.*"/>
<property name="advice" ref="around"/>
</bean>
<!-- 自动生成代理 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
</beans>

Java Spring-传统AOP开发的更多相关文章

  1. Spring的AOP开发的相关术语

    转载自 https://www.cnblogs.com/ltfxy/p/9873618.html SpringAOP简介: AOP思想最早是由AOP联盟组织提出的.Spring使用这种思想最好的框架. ...

  2. 十一 Spring的AOP开发的相关术语

    SpringAOP简介: AOP思想最早是由AOP联盟组织提出的.Spring使用这种思想最好的框架. Spring的AOP有自己实现的方式,但是非常繁琐.AspectJ是一个AOP框架,Spring ...

  3. Spring的AOP开发(基于AspectJ的XML方式)

    Spring的AOP的简介: AOP思想最早是由AOP联盟组织提出的.Spring是使用这种思想最好的框架 Spring的AOP有自己实现的方式(非常繁琐). Aspect是一个AOP的框架, Spr ...

  4. Spring的AOP开发入门,Spring整合Junit单元测试(基于ASpectJ的XML方式)

    参考自 https://www.cnblogs.com/ltfxy/p/9882430.html 创建web项目,引入jar包 除了基本的6个Spring开发的jar包外,还要引入aop开发相关的四个 ...

  5. Spring的AOP开发(基于ApsectJ的注解)

    创建项目,导包 编写目标类并配置 创建OrderDao package com.rick.aop.demo1; public class OrderDao { public void save() { ...

  6. Java : Spring基础 AOP

    简单的JDK动态代理例子(JDK动态代理是用了接口实现的方式)(ICar是接口, GoogleCar是被代理对象, MyCC是处理方法的类): public class TestCar { publi ...

  7. 十二 Spring的AOP开发入门,整合Junit单元测试(AspectJ的XML方式)

    创建web项目,引入jar包 引入Spring配置文件

  8. Spring的AOP基于AspectJ的注解方式开发3

    上上偏博客介绍了@Aspect,@Before 上篇博客介绍了spring的AOP开发的注解通知类型:@Before,@AfterThrowing,@After,@AfterReturning,@Ar ...

  9. Spring 实践 -AOP

    Spring 实践 标签: Java与设计模式 AOP引介 AOP(Aspect Oriented Programing)面向切面编程采用横向抽取机制,以取代传统的纵向继承体系的重复性代码(如性能监控 ...

随机推荐

  1. 微软官方:SELECT语句逻辑处理顺序

    以下步骤显示SELECT 语句的逻辑处理顺序或绑定顺序.此顺序确定在一个步骤中定义的对象何时可用于后续步骤中的子句. 例如,如果查询处理器可以绑定到(访问)在FROM 子句中定义的表或视图,则这些对象 ...

  2. springMVC各个包下的作用

    spring的jar各包作用spring.jar是包含有完整发布的单个jar包,spring.jar中包含除了spring-mock.jar里所包含的内容外其它所有jar包的内容,因为只有在开发环境下 ...

  3. T-SQL数据库备份

    /*1.--得到数据库的文件目录 @dbname 指定要取得目录的数据库名 如果指定的数据不存在,返回安装SQL时设置的默认数据目录 如果指定NULL,则返回默认的SQL备份目录名 */ /*--调用 ...

  4. docker环境搭建centos+jdk+tomcat_CENTOS篇

    前言 (1)写在前面的话,鉴于在linux或类unix系统中安装jdk+tomcat等环境,没有什么经验,所以选择在docker容器中安装之,以防止安装失败无法恢复系统 (2)需要下载对应的系统的do ...

  5. Drainage Ditches---hdu1532(最大流)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1532 题意: 每次下雨的时候,农场主John的农场里就会形成一个池塘,这样就会淹没其中一小块土地,在这 ...

  6. Python性能鸡汤(转)

    英文原文:http://blog.monitis.com/index.php/2012/02/13/python-performance-tips-part-1/ 英文原文:http://blog.m ...

  7. [GDAL]编译64位GDAL1.10

    环境VS2010,swigwin-2.0.11 1. 打开nmake.opt文件,找到SWIG=swig.exe这一句,假如没有将swig的目录添加到环境变量中,那么将这句后面的swig.exe修改为 ...

  8. [py]python的深拷贝和浅拷贝

    Python深复制浅复制or深拷贝浅拷贝 简单点说 copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. copy.deepcopy 深拷贝 拷贝对象及其子对象 用一个简单的例子说明 ...

  9. R语言基本语法

    R语言基本语法 基本数据类型 数据类型 向量 vector 矩阵 matrix 数组 array 数据框 data frame 因子 factor 列表 list 向量 单个数值(标量)没有单独的数据 ...

  10. c/c++ json使用

    比如出名的有CJson,c++一般用jsoncpp http://sourceforge.net/projects/jsoncpp/ jsoncpp:http://www.cnblogs.com/fe ...