Spring AOP API
来源:互联网 发布:mac如何复制粘贴 编辑:程序博客网 时间:2024/06/03 20:19
( 基础概念见 Spring AOP基础部分)
Spring AOP API是Spring的基础,必须要了解掌握。在这里,说三个内容:Pointcut / Advice / ProxyFactoryBean
一 Pointcut 切入点
切入点作为一个接口,有几个实现类。
实现方式:使用NameMatchMethodPointcut,根据方法名字进行匹配,含有成员变量:mappedNames,匹配的方法名集合。
<.bean id=”pointcutBean” class=”org.springframework.aop.support.NameMatchMethodPointcut”> <propertyname=”mappedNames”> <list> <value>sa*</value> </list> </property></bean>
二 Advice
Advice源代码参照链接(https://github.com/TerenceJIng/javaLearn)
1 Throws advice
如果连接点抛出异常,throws advice在连接点返回后调用,如果throws-advice的方法抛出异常,那么它将覆盖原有异常。
接口org.springframework.aop.ThrowsAdvice不包含任何方法,仅仅是一个声明,实现类需要实现类似下面的方法:
void afterThrowing([Mthod,args,target],ThrowableSubclass);
public class TerenceThrowsAdvice implements ThrowsAdvice { public void afterThrowing(Exception ex) throws Throwable { System.out.println("TerenceThrowsAdvice afterThrowing1"); } public void afterThrowing(Methodmethod,Object[] args,Object target,Exception ex) throws Throwable { System.out.println("TerenceThrowsAdvice afterThrowing2:"+method.getName()+" "+ target.getClass().getName()); }}
2 After Returning advice
后置通知必须实现org.springframework.aop.AfterReturningAdvice接口,可以访问返回值(但是不能对其修改)、被调用的方法、方法的参数和目标。如果抛出异常,将会抛出拦截器链,替代返回值。
public class TerenceAfterReturningAdvice implements AfterReturningAdvice { public void afterReturning(Object returnValue,Method method, Object[] arga, Object target) throws Throwable { System.out.println("TerenceAfterReturningAdvice:"+method.getName()+" "+ target.getClass().getName()+" "+returnValue); }}
3 Interception around advice
Spring的切入点模型是的切入点可以单路的于advice重用,以针对不同的advice可以使用相同的切入点。
public class TerenceMethodInterceptor implements MethodInterceptor { public Object invoke(MethodInvocation invocation)throws Throwable { System.out.println("TerenceMethodInterceptor 1:"+invocation.getMethod().getName()+" " + invocation.getStaticPart().getClass().getName() ); Object obj=invocation.proceed(); System.out.println("TerenceMethodInterceptor 2:"+obj); return obj; }}
4 Introduction advice
Spring把引入通知作为一种特殊的拦截通知,需要IntroductionAdvisor和IntroductionInterceptor,仅适用于类,不能把任何切入点一起使用。
5 Advisor API in Spring
Advisor是仅包含一个切入点表达式关联的单个通知的方面,除了introductions,advisor可以用于任何通知
Org.springframework.aop.support.DefaultPointcutAdvisor是最常用的advisor类,它可以语MethodInterceptor,BeforeAdvice或者ThrowsAdvice一起使用它可以混合在Spring同一个AOP代理的Advisor和Advice。
三 ProxyFactoryBean
ProxyFactoryBean是Spring AOP 代理的基础核心类。
1 创建SpringAOP代理
创建SpringAOP代理的基创建SpringAOP本方法是用org.springframework.aop.framework.ProxyFactoryBean,通过使用该类,可以完全的控制切入点和通知(advice)以及她们的顺序。
简单的说,就是getBean(BeanId)的时候,BeanId对应配置类是ProxyFactoryBean,但是获取的并不是该类,而是通过该类的getObject()方法创建的对象,这个方法创建的是一个AOP代理包装了一个目标对象。
通过这种方式达到代理的目的。
- 使用ProxyFactoryBean或者其他IoC相关类来创建AOPdialing的最大的好处也是最重要的额好处就是通知和切入点可以有IoC来管理。
- 如果被代理类没有实现任何借口,则使用CGLIB代理;如果有实现接口,则使用JDK代理
- 但是,被代理类有没有实现接口,只要设置ProxyTargetClass为True,就可以强制使用CGLIB。
- 如果目标类实现了一个或者多个接口,那么创建代理的类型将一来ProxyFactoryBean的配置。
如果ProxyFactoryBean的proxyInterfaces属性被设置为要给或者多个全限定接口名(所谓的全限定接口名是指定一个类名的时候带上包名类名,如:com.terence.aop.advice.api.TerenceBefore),此时将使用基于JDK的代理,基于JDK的代理会被创建。
那么,该类的获取配置项里面应该加入目标类属性target和包含通知列表的拦截属性interceptorNames:
<bean id="bizLogicImpl"class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <ref bean="bizLogicImplTarget"/> </property> <property name="interceptorNames"> <list> <value>defaultAdvisor</value> <value>terenceAfterReturningAdvice</value> <value>terenceMethodInterceptor</value> <value>terenceThrowsAdvice</value> </list> </property> </bean>
由上述配置可知,则必须首先声明目标类Bean和各个通知或拦截Bean.
<bean id="terenceBeforeAdvice"class="com.terence.aop.api.TerenceBeforeAdvice"/> <bean id="terenceAfterReturningAdvice"class="com.terence.aop.api.TerenceAfterReturningAdvice"/> <bean id="terenceMethodInterceptor"class="com.terence.aop.api.TerenceMethodInterceptor"/> <bean id="terenceThrowsAdvice"class="com.terence.aop.api.TerenceThrowsAdvice"/> <bean id="bizLogicImplTarget"class="com.terence.aop.api.BizLogicImpl"/> <bean id="pointcutBean"class="org.springframework.aop.support.NameMatchMethodPointcut"> <property name="mappedNames"> <list> <value>sa*</value> </list> </property> </bean> <bean id="defaultAdvisor"class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice" ref="terenceBeforeAdvice"/> <property name="pointcut" ref="pointcutBean"/> </bean>
类似于上述的配置,ProxyFactoryBean的proxyInterfaces属性没有被设置,但是目标类实现了一个(或者多个)接口,那么ProxyFactoryBean将自动监测到这个目标类已经实现了至少一个接口,创建一个基于JDK的代理。
完整的配置文件spring-aop-api.xml:
<?xml version="1.0"encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="terenceBeforeAdvice" class="com.terence.aop.api.TerenceBeforeAdvice"/> <bean id="terenceAfterReturningAdvice" class="com.terence.aop.api.TerenceAfterReturningAdvice"/> <bean id="terenceMethodInterceptor" class="com.terence.aop.api.TerenceMethodInterceptor"/> <bean id="terenceThrowsAdvice" class="com.terence.aop.api.TerenceThrowsAdvice"/>
<!--第二部分--><bean id="bizLogicImplTarget"class="com.terence.aop.api.BizLogicImpl"/> <bean id="pointcutBean"class="org.springframework.aop.support.NameMatchMethodPointcut"> <property name="mappedNames"> <list> <value>sa*</value> </list> </property> </bean> <bean id="defaultAdvisor"class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="advice" ref="terenceBeforeAdvice"/> <property name="pointcut" ref="pointcutBean"/> </bean> <bean id="bizLogicImpl"class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <ref bean="bizLogicImplTarget"/> </property> <property name="interceptorNames"> <list> <value>defaultAdvisor</value> <value>terenceAfterReturningAdvice</value> <value>terenceMethodInterceptor</value> <value>terenceThrowsAdvice</value> </list> </property> </bean>
如果设置了ProxyFactoryBean的proxyInterfaces属性,则可以用另外一种配置方式,上述配置文件中第2部分替换为下述配置:
<!--指定了实现类的接口,所以会用JDK的代理--><bean id="bizLogicImplTarget"class="com.terence.aop.api.BizLogicImpl"/> <bean id="bizLogicImpl"class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>com.terence.aop.api.BizLogic</value> </property> <property name="target"> <ref bean="bizLogicImplTarget"/> </property> <property name="interceptorNames"> <list> <value>terenceBeforeAdvice</value> <value>terenceAfterReturningAdvice</value> <value>terenceMethodInterceptor</value> <value>terenceThrowsAdvice</value> </list> </property></bean>
另外一点:可以使用匿名内部bean来隐藏目标和代理之间的区别。
可以通过直接定义目标bean,将其赋值给Target。
将配置
<propertyname="target">
<refbean="bizLogicImplTarget"/>
</property>
替换为
<propertyname="target">
<bean class="com.terence.aop.api.BizLogicImpl"/>
</property>
CGLIB代理的工作原理是在运行时生成目标类的子类,Spring配置这个生成的子类委托方法调用原来的目标,子类是通过实现Decorator模式,织入通知。
CGLIB的代理对用户是透明的,需要注意:
-final方法不能被通知,因为他们不能被覆盖
-不用把CGLIB添加到classpath中,在Spring3.2中,CGLIB被重新包装并并包含在Spring核心的JAR中(即基于CGLIB的AOP就像JDK动态代理一样开箱即用)。
用*做匹配,是将匹配的所有拦截器加入通知链。
<bean id="bizLogicImpl"class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <ref bean="bizLogicImplTarget"/> </property> <property name="interceptorNames"> <list> <value>terence*</value> </list> </property> </bean>
2 简化的proxy定义
使用父子bean定义,以及内部bean定义,可能会带来更加简洁的代理定义。(抽象属性标记父bean,将其定义为抽象bean,不能被实例化。)
<!-- 实现方式三 -->
<!-- 通过简化的Proxy定义 -->
<bean id="baseProxyBean"class="org.springframework.aop.framework.ProxyFactoryBean" lazy-init="true"abstract="true"></bean> <!--指向父抽象Bean--> <bean id="bizLogicImpl"parent="baseProxyBean"> <property name="target"> <bean class="com.terence.aop.api.BizLogicImpl"/> </property> <property name="proxyInterfaces"> <value>com.terence.aop.api.BizLogic</value> </property> <property name="interceptorNames"> <list> <value>terenceBeforeAdvice</value> <value>terenceAfterReturningAdvice</value> <value>terenceMethodInterceptor</value> <value>terenceThrowsAdvice</value> </list> </property></bean>
3 使用ProxyFactory
好处是使用SpringAOP而不必依赖于SpringIOC容器。
ProxyFactory factory=new ProxyFactory(myBusinessInterfaceImpl); factory.addAdvice(myBusinessInterceptor); factory.addAdvisor(myAdvisor); MyBusinessInterface tb=(MyBusinessInterface)factory.getProxy();
大多数情况下最佳实践是用IOC容器创建AOP代理, 虽然可以用这种硬编码方式实现,但是Spring推荐使用配置或注解方式实现。
4 使用auto-proxy
Spring也允许使用“自动代理”的bean定义,它可以自动代理选定的bean,这是建立在Spring的“bean post processor”功能基础上的(在加载bean的时候就可以修改),是通过使用BeanNameAutoProxyCreator实现。
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames" value="jdk*,onlyJdk"> </property> <property name="interceptorNames"> <list> <value>myInterceptor</value> </list> </property></bean>
5 使用DefaultAdvisorAutoProxyCreator
如果声明了DefaultAdvisorAutoProxyCreator,当前IOC容器中自动应用,来到创建代理的效果,不用显示声明应用advisor的bean定义。
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/> <bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor"> <property name="transactionInterceptor" ref="transactionInterceptor"/> </bean> <bean id="customAdvisor" class="com.terence.aop.MyAdvisor"/> <bean id="businessObject1" class="com.terence.aop.BusinessObject1"> <property name=".."></property> </bean><bean id="businessObject2"class="com.terence.aop.BusinessObject2"/>
- spring-AOP-API
- Spring AOP API
- [JAVA] Spring AOP API简述
- Spring API级别对AOP的支持
- Spring AOP实现(API实现)
- Spring入门(AOP API、ProxyFactoryBean其一)
- Spring入门(AOP API、ProxyFactoryBean其二)
- 6、spring 入门—Spring AOP API介绍
- Spring AOP 使用注解为API引入新功能
- spring aop 中 org.aspectj.lang.JoinPoint-中文简要API
- Spring入门(AOP API,ProxyFactoryBean其三)
- AOP、Spring的AOP
- AOP--Spring AOP
- Spring AOP 嵌套AOP
- Spring面向切面编程——Spring实现AOP方式——通过Spring API实现
- spring AOP
- Spring AOP
- Spring AOP
- PAT 1007 素数对猜想
- hibernate一对一、一对多、多对多的配置方法
- 打好企业营销战的三要素:战略、专业、实施
- C语言 输出字符03
- easyui-tree 实现checkbox 单选
- Spring AOP API
- The Largest Generation (25)
- C语言输出字符04
- 代码使得分别出现StackOverflowError和OutOfMemoryError
- 在eclipse捣鼓java项目时library加载与webcontent下的web-inf下lib加载jar包的区别
- 数据结构-栈和队列
- Linux文件权限
- 如何构造一个高效且为我们所用的优质社群?
- C语言输出字符05