Java Spring-传统AOP开发
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开发的更多相关文章
- Spring的AOP开发的相关术语
转载自 https://www.cnblogs.com/ltfxy/p/9873618.html SpringAOP简介: AOP思想最早是由AOP联盟组织提出的.Spring使用这种思想最好的框架. ...
- 十一 Spring的AOP开发的相关术语
SpringAOP简介: AOP思想最早是由AOP联盟组织提出的.Spring使用这种思想最好的框架. Spring的AOP有自己实现的方式,但是非常繁琐.AspectJ是一个AOP框架,Spring ...
- Spring的AOP开发(基于AspectJ的XML方式)
Spring的AOP的简介: AOP思想最早是由AOP联盟组织提出的.Spring是使用这种思想最好的框架 Spring的AOP有自己实现的方式(非常繁琐). Aspect是一个AOP的框架, Spr ...
- Spring的AOP开发入门,Spring整合Junit单元测试(基于ASpectJ的XML方式)
参考自 https://www.cnblogs.com/ltfxy/p/9882430.html 创建web项目,引入jar包 除了基本的6个Spring开发的jar包外,还要引入aop开发相关的四个 ...
- Spring的AOP开发(基于ApsectJ的注解)
创建项目,导包 编写目标类并配置 创建OrderDao package com.rick.aop.demo1; public class OrderDao { public void save() { ...
- Java : Spring基础 AOP
简单的JDK动态代理例子(JDK动态代理是用了接口实现的方式)(ICar是接口, GoogleCar是被代理对象, MyCC是处理方法的类): public class TestCar { publi ...
- 十二 Spring的AOP开发入门,整合Junit单元测试(AspectJ的XML方式)
创建web项目,引入jar包 引入Spring配置文件
- Spring的AOP基于AspectJ的注解方式开发3
上上偏博客介绍了@Aspect,@Before 上篇博客介绍了spring的AOP开发的注解通知类型:@Before,@AfterThrowing,@After,@AfterReturning,@Ar ...
- Spring 实践 -AOP
Spring 实践 标签: Java与设计模式 AOP引介 AOP(Aspect Oriented Programing)面向切面编程采用横向抽取机制,以取代传统的纵向继承体系的重复性代码(如性能监控 ...
随机推荐
- 微软官方:SELECT语句逻辑处理顺序
以下步骤显示SELECT 语句的逻辑处理顺序或绑定顺序.此顺序确定在一个步骤中定义的对象何时可用于后续步骤中的子句. 例如,如果查询处理器可以绑定到(访问)在FROM 子句中定义的表或视图,则这些对象 ...
- springMVC各个包下的作用
spring的jar各包作用spring.jar是包含有完整发布的单个jar包,spring.jar中包含除了spring-mock.jar里所包含的内容外其它所有jar包的内容,因为只有在开发环境下 ...
- T-SQL数据库备份
/*1.--得到数据库的文件目录 @dbname 指定要取得目录的数据库名 如果指定的数据不存在,返回安装SQL时设置的默认数据目录 如果指定NULL,则返回默认的SQL备份目录名 */ /*--调用 ...
- docker环境搭建centos+jdk+tomcat_CENTOS篇
前言 (1)写在前面的话,鉴于在linux或类unix系统中安装jdk+tomcat等环境,没有什么经验,所以选择在docker容器中安装之,以防止安装失败无法恢复系统 (2)需要下载对应的系统的do ...
- Drainage Ditches---hdu1532(最大流)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1532 题意: 每次下雨的时候,农场主John的农场里就会形成一个池塘,这样就会淹没其中一小块土地,在这 ...
- Python性能鸡汤(转)
英文原文:http://blog.monitis.com/index.php/2012/02/13/python-performance-tips-part-1/ 英文原文:http://blog.m ...
- [GDAL]编译64位GDAL1.10
环境VS2010,swigwin-2.0.11 1. 打开nmake.opt文件,找到SWIG=swig.exe这一句,假如没有将swig的目录添加到环境变量中,那么将这句后面的swig.exe修改为 ...
- [py]python的深拷贝和浅拷贝
Python深复制浅复制or深拷贝浅拷贝 简单点说 copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. copy.deepcopy 深拷贝 拷贝对象及其子对象 用一个简单的例子说明 ...
- R语言基本语法
R语言基本语法 基本数据类型 数据类型 向量 vector 矩阵 matrix 数组 array 数据框 data frame 因子 factor 列表 list 向量 单个数值(标量)没有单独的数据 ...
- c/c++ json使用
比如出名的有CJson,c++一般用jsoncpp http://sourceforge.net/projects/jsoncpp/ jsoncpp:http://www.cnblogs.com/fe ...