面向切片
术语
切面:切面是要实现的交叉功能.
联接点:应用程序执行过程中插入切面的地方.
通知:通知切面的实际实现.
切入点:定义了通知应改应用在哪些联接点.
引入:为已存在类添加新方法和属性.
目标对象:被通知的对象.
代理:将通知应用到目标对象后创建的对象.
织入,将切面应用到目标对象从而创间一个新的代理对象的过程.
创建通知
通知包含了切面的逻辑.在创建一个通知对象的时候,是在编写实现交叉功能的代码.
Spring通知类型:
Around
org.aopalliance.intercept.MethodInterceptor 拦截对目标对象方法的调用.
public interface MethodInterceptor extends Interceptor{
Object invoke (MethodInvocation invocation)throws Throws Throwable;
}
区别:(1)MethodInterceptor 能构控制目标方法是否真的被调用.
通过调用MethodInvocation.proceed()方法来调用目标方法.
MehtodBeforeAdvice总是被调用,除非抛出异常;
(2)你可以控制返回的对象,可以返回一个与proceed()方法返回对象完全不同的对象.
AfterReturningAdvice不可以返回不同的对象;
Before
org.springframework.aop.BeforeAdvice 在目标方法被调用之前调用
public interface MethodBeforeAdvice{
void before(Method method,Object[] args, Object target)throws Throwable
}
接口为我们提供了货得目标方法,参数,以及目标对象的机会.参数和目标对象是不可以改变的;
返回值为void.返回后,目标方法将被调用.为一可以阻止目标方法被调用的途径是抛出异常;
After
org.springframework.aop.AfterReturningAdvice在目标方法被调用之后调用
public interface AfterReturningAdvice {
void afterReturning(Object return value,Method method,Object[] args,Object target) throws Throwable
}
可以获得被通知的方法的返回值.这个接口也返回空.不可以替换返回值.
Throws org.springframework.aop.ThrowsAdvice 当目标方法抛出异常时调用
例子
<beans>
<bean id="target_id" class="target_class"/>
<bean id="welcomeAdvice_id" class="advice_class"/>
<bean id="proxy_id" class="org.springframework.aop.framework.ProxyFactoryBean
">
<property name="proxyInterfaces">
<value>interface to be implemented;
</value>
</property>
<property name="interceptorNames">
<list>
<value>welcomeAdvice_id</value>
</list>
</property>
<property name="target">
<ref bean="target_id"/>
</property>
</bean>
</beans>
定义切入点
表达在应用系统的什么地方应用这些通知 ; 决定了一个特定类的特定方法是否满足一条特定规则 . 符合 , 通知就应用到该方法上 .
在 Spring 中定义切入点
Spring 根据需要织入通知的类和方法来定义切入点 .
Spring 切入点框架的核心 Pointcut;
Public interface Pointcut{
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
Public interface ClassFilter{
Boolean matches(Class clazz); // 决定传进来的类是否应该被通知
}
Public interface MethodMatcher{
Boolean matches(Method m, Class targetClass);// 决定一个方法是否被通知
Public boolean isRuntime();// 决定 MethodMatcher 是动态还是静态
Public Boolean matches(Method m, Class target, Object[] args);// 目标对象方法被调用时 , 次方法被调用 ( 动态切入点 )
}
理解Advisor
Advisor由定义切面行为的通知(Advice)和定义切面在什么地方执行的切入点(Pointcut)组合而成的.
Public interface pointcutAdvisor{
Pointcut getPointcut();
Advice getAdvice();
}
(1)静态切入点
静态切入点只在代理创建的时候执行一次而不是在运行时每次方法调用都执行,所以性能比动态切入点好;
Spring为创建静态切入点提供了一个父类 StaticMethodMatcherPointcut,实现其中的isMatch方法即可;
一般,Spring提供的静态切入点就可以了,NameMatchMethodPointcut,当被调用方法的名字与给出的映射名字匹配时,切点才匹配
Public void setMappedName(String)
Public void setMappedNames(String[])
例子:
<beans>
<bean id=”target_class” class=””/>
<bean id=”advice_class” class=””/>
<bean id=”advisor_config” class=”org.springframework.aop.support.NameMatchMethodPointcutAdvisor”>
<property name=”mappedName”>
<value>order*</value>
</property>
<property name=”advice”>
<ref bean=”advice_class”>
</property>
</bean>
<bean id=”proxy_class” class=”org.springframework.aop.framework,ProxyFactoryBean”>
<property name=”proxyInterfaces”>
<value>interface_class_of _target_class</value>
</property>
<property name=”interceptorNames”>
<list>
<value>advisor</value>
</list.
</property>
<property name=”target”>
<value ref=”target_class”>
</property>
</bean>
</beans>
(2)正则表达式切入点
常用的符号
. 匹配任何单个字符
+ 匹配前一个字符一次或多次
* 匹配前一个字符0次或多次
\ 匹配任何正则表达式符号
<beans>
<bean id="target_class" class=""/>
<bean id="target_class" class=""/>
<bean id="advice_class" class="">
<property name="pattern">
<value></value>
</property>
<property name="advice">
<ref bean=
"advice_class"/>
</property>
</bean>
<bean id="proxy_class" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
</property>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
<property name="target">
<value ref
="target_class">
</property>
</bean>
</beans>
创建引入
与其他类型的通知不同,引入影响整个类,而不是方法; 通过给需要消息的类添加方法和属性来实现.
Spring通过IntroductionMehtodInterceptor实现引入. 该接口中添加了一个方法
Boolean implementsInterface(Class intf);
当方法返回true,对用这个接口声明的方法的任何调用将被委托给InroductionMethodInterceptor的invoke()方法.
自动代理
BeanNameAutoProxyCreator为匹配一系列名字的Bean自动创建代理.与NameMethodMatcherPointcut类似;
<bean id="performanceThredsholdInterceptor" class="**.**.PerformanceThresholdInterceptor">
</bean>
<bean id="" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value> *Service</value>
</list>
</property>
<property name="interceptorNames">
<value>performanceThredsholdInterceptor</value>
</property>
</bean>
DefaultAdvisorAutoProxyCreator 实现了BeanPostProcessor接口,
applicationcontext在读入所有的bean的配置信息后,
DefaultAdvisorAutoProxyCreator扫描上下文,寻找Advisor,并切入合适的点.
<bean id="interceptor" class="interceptor_class"/>
<constructor-arg>
<value></value>
</constructor-arg>
</bean>
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<bean class="performanceThresholdInterceptor"/>
</property>
<property name="pattern">
<value></value>
</property>
</bean>
<bean id="" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
ProxyFactoryBean
属性
target 代理的目标对象
proxyInterfaces 代理应改实现的接口列表
interceptorNames 需要应用到目标对象上的通知Bean的名字,可以是拦截器\Advisor或者其他通知类型
的名字,这个属性必需按照BeanFactory中使用的顺序设置