Spring(六)
来源:互联网 发布:php有什么用 编辑:程序博客网 时间:2024/05/16 01:51
Spring面向方面编程(AOP)
2016/6/19 12:51:27 seventeenWen
AOP总结
虽然可以通过PreformanceHandler实现横切逻辑的动态织入,但还是有不足之处:
- 目标类的所有方法都添加了横切逻辑,而有时,并不是所有的方法都需要横切逻辑。
- 通过硬编码的方式织入了横切逻辑的织入点,在业务方法开始前和结束后织入代码。
- 需要手工编写代理对象的创建过程,为不同类创建代理是,需要编写不同的代码。
Spring的AOP便解决了上面的三点,
- 通过Pointcut(切点)指定了在哪些类的哪些方法上织入横切逻辑。
- 通过Advice(增强)描述横切逻辑的方法和具体织入的点(方法前,方法后,方法的两端)。
- 通过Advisor(切面)将Pointcut和Advice两者组装起来。
Spring的Advice(增强)
- 前置增强(org.springframework.aop.BeforeAdvice):表示在方法前增强。
BeeforeAdvice接口只定义了一个方法void before(Method method, Object[] args, Object target) throws Throwable;
三个参数:
- method:目标类的方法
- args:目标类传入的参数
- obj:目标类的对象
Spring的ProxyFactory
代理工厂(ProxyFactory)
Spring源码(org.springframework.aop.framework.AopProxy)中定义类这么个接口:
public interface AopProxy { Object getProxy(); Object getProxy(ClassLoader classLoader); }
它有两个实现类JdkDynamicAopProxy和CglibAopProxy,一个是使用JDK动态代理技术,一个是使用Cglib代理技术实现的。如果通过ProxyFactory的setInterfaces指定接口进行代理则使用JDK代理,如果针对类进行代理则使用CGLib技术
Spring中的配置
<bean id="ServeAdvice" class="com.spring.proxy.test.ServeAdviceBefpreAdvice"> <bean id="target" class="com.spring.proxy.test.target"><bean id="obj" class="org.springframework.aop.framework.ProxyFactoryBean" P:proxyinterfaces="com.spring.proxy.test.interface"//指定需要代理的接口 P:interceptorNames="adviceMethod"//指定使用的增强方法 p:target-ref="target"//指定对哪个Bean进行增强
其他属性:
- target:代理的目标对象
- proxyInterfaces:代理需要实现的接口
- interceptorNames:需要植入目标对象的Bean列表,这些Bean必须实现了org.aopalliance.intercept.MethodInterceptor或org.springframework.aop.Advisor,配置中的顺序代表调用的顺序
- singleton:返回来的对象是否为单例
- optimeize:设置为true时,强制使用CGLib代理
- proxyTargetClass:是否对类进行代理,设置为true时,使用CGLib代理
- 后置增强(org.springframework.aop.AfterReturningAdvice):表示在方法后增强。
AfterReturningAdvice接口只定义了一个方法void afterReturning(Method method, Object[] args, Object target) throws Throwable;
\ - 环绕增强(org.springframework.aop.MethodInterceptor):表示方法环绕增强(即在方法前后调用),
Object invoke(MethidInvocation invocation) throws Throwable
异常抛出增强(org.springframework.aop.ThrowsAdvice) :表示异常抛出增强,ThrowsAdvice接口没有任何方法,它是一个标识接口,我们必须以
void afterThrowing(Methid method,Onject[] args,Object target,Throwable);
这么定义异常的抛出,方法名必须是afterThrowing,前两个参数可选要么都填,要么都不填,最后Throwable参数必须添加,并且是Throwable或它的子类。
- 引介增强(org.springframework.aop.support.DelegatingIntriductionInterceptor):它不是在目标方法周围织入增强,而是为目标类创建新的方法和属性,所以引介增强的连接点是类级别的,而非方法级别的,即即使目标类没有实现某个接口,同过引介增强可以为目标类创建实现某接口的代理。通过扩展DelegatingIntroductionInterceptor实现类来定义自己的引介增强类。
Spring的切面
如果我们想要有选择的织入到目标类的某些方法中,就需要使用切点进行连接点的定位。
Spring通过(org.springframework.Pointcut)接口描述切点,接口有两个方法:
ClassFilter getClassFilter();MethodMatcher getMethodMatcher();
ClassFilter中定义了一个方法:
boolean matches(Class<?> clazz);
clazz代表一个被检测类,这个方法判断是否匹配过滤条件。Spring支持两种匹配器,一种静态方法匹配器,运行期间只会匹配一次,根据方法的名称和入参的顺序匹配,一种动态方法匹配器。会在运行期间检查方法的值。每次调用方法都会匹配一次。
MethodMatcher isRuntime();
方法返回true,代表动态方法,返回false,代表静态方法。
切点类型
- 静态方法切点(org.springframework.aop.support.StaticMethodMatcherPointcut):默认匹配所有的类,有两个子类NameMethodPointcut:(简单的根据字符串进行匹配)和AbstractRegexpMethodPointcut(正则表达式进行匹配)
- 动态方法切点(org.springframework.aop.support.DynamicMethodMatcherPointcut):默认匹配所有类,
- 流程切点(org.springframework.aop.support.ControlFlowPointcut):它的实现类表示控制流程切点,
- 复合切点(org.springframework.aop.support.ComposablePointcut):它的实现类是为了创建多个切点的方便提供类
切面类型
Spring中,切面有三种:
1. Advisor:只代表一个切面,是个抽象的接口,代表切面的概念。
2. PointcutAdvisor:代表具有切点的切面,它包含两个类Advice和Pointcut
3. IntroductionAdvisor:代表引介切面,它是应用在类的层面上
静态方法切点Demo
public class WaiterImp implements Waiter{public void greetTo(String name){ System.out.println("Waiter greet to "+name+"....");}public void serveTo(String name){ System.out.println("waiter serving to "+name+"....");}}public class SellerImp implements Seller{public void greetTo(String name){ System.out.println("seller greet to "+name+"...");}}//定义切面public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor{private static final long serialVersionUID = 1L;/* (non-Javadoc) * * 匹配方法名称为serveTo的方法 * @see org.springframework.aop.MethodMatcher#matches(java.lang.reflect.Method, java.lang.Class) */public boolean matches(Method method, Class<?> targetClass) { return "serveTo".equals(method.getName());}public ClassFilter getClassFilter(){ return new ClassFilter(){ /* (non-Javadoc) * * 类是Waiter的子类或实现类的匹配 * * @see org.springframework.aop.ClassFilter#matches(java.lang.Class) */ public boolean matches(Class<?> clazz) { return Waiter.class.isAssignableFrom(clazz); } };}}//定义增强public class GreetBeforeAdvice implements MethodBeforeAdvice{public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName()+"."+method.getName()); String clientName=(String)args[0]; System.out.println("How are you"+clientName+".");}}
beans.xml配置
<bean id="waiterTarget" class="com.spring.advisor.WaiterImp"/><bean id="sellerTarget" class="com.spring.advisor.SellerImp"/><bean id="greetingAdvice class="com.spring.advisor.GreetBeforeAdvice" /><bean id="greetingAdvisor" class="com.spring.advisor.GreetingAdvisor" p:advice-ref="greetingAdvice"/><bean id="parent" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="greetingAdvisor" p:proxyTargetClass="true"/><bean id="waiter" parent="parent" p:target-ref="waiterTarget"/><bean id="seller" parent="parent" p:target-ref="sellerTarget"/>
测试类Demo
public class Run { @Test public void RunTest(){ ApplicationContext ctx =new ClassPathXmlApplicationContext("beans.xml"); WaiterImp waiter =(WaiterImp) ctx.getBean("waiter"); SellerImp seller =(SellerImp) ctx.getBean("seller"); waiter.greetTo("seventeenWen"); waiter.serveTo("seventeenWen"); seller.greetTo("seventeenWen"); }}
结果:
Waiter greet to seventeenWen....com.spring.advisor.WaiterImp.serveToHow are youseventeenWen.waiter serving to seventeenWen....seller greet to seventeenWen...
- Spring(六)
- 六、Spring管理数据源
- 学习Spring笔记六
- Spring+Mina(六)
- spring security(六)
- 初识spring(六)
- 使用Spring(六)集合
- Spring Security教程(六)
- 六.Spring AOP浅析
- Spring Boot学习(六)
- Spring Boot (六) JdbcTemplate
- Spring编程<六>
- Spring学习笔记(六)
- 六、Struts spring hibernate集成
- Spring技术入门(六)
- spring的继承使用<六>
- Spring学习笔记(六)
- 六、Spring Boot日志管理
- ImportError: No module named examples.tutorials.mnist
- 基于Android Studio的内存泄漏检测与解决全攻略
- php 5.3.10 + CI3 PDO注入测试
- 嵌入式学习-uboot-lesson1-链接器脚本基础知识
- JNIEnv类型中方法的使用
- Spring(六)
- Commom JS
- 删除文件,若文件所在目录下只有一个文件则递归删除文件所在目录,直到删除的所在目录下有两个文件或者文件夹
- mysql 的触发器
- Android内存优化总结【整理】
- 高德地图——标记
- C++实现快速排序(源代码)
- 使用mybatis的逆向工程(xml方式)创建java代码
- linux 安装ffmpeg 非yasm yum安装