Spring(六)

来源:互联网 发布:php有什么用 编辑:程序博客网 时间:2024/05/16 01:51

Spring面向方面编程(AOP)

2016/6/19 12:51:27 seventeenWen

AOP总结


虽然可以通过PreformanceHandler实现横切逻辑的动态织入,但还是有不足之处:

  1. 目标类的所有方法都添加了横切逻辑,而有时,并不是所有的方法都需要横切逻辑。
  2. 通过硬编码的方式织入了横切逻辑的织入点,在业务方法开始前和结束后织入代码。
  3. 需要手工编写代理对象的创建过程,为不同类创建代理是,需要编写不同的代码。

Spring的AOP便解决了上面的三点,

  • 通过Pointcut(切点)指定了在哪些类的哪些方法上织入横切逻辑。
  • 通过Advice(增强)描述横切逻辑的方法和具体织入的点(方法前,方法后,方法的两端)。
  • 通过Advisor(切面)将Pointcut和Advice两者组装起来。

Spring的Advice(增强)

  1. 前置增强(org.springframework.aop.BeforeAdvice):表示在方法前增强。
    BeeforeAdvice接口只定义了一个方法
    void before(Method method, Object[] args, Object target) throws Throwable;

三个参数:

  1. method:目标类的方法
  2. args:目标类传入的参数
  3. 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代理

  1. 后置增强(org.springframework.aop.AfterReturningAdvice):表示在方法后增强。
    AfterReturningAdvice接口只定义了一个方法
    void afterReturning(Method method, Object[] args, Object target) throws Throwable;\
  2. 环绕增强(org.springframework.aop.MethodInterceptor):表示方法环绕增强(即在方法前后调用),
    Object invoke(MethidInvocation invocation) throws Throwable
  3. 异常抛出增强(org.springframework.aop.ThrowsAdvice) :表示异常抛出增强,ThrowsAdvice接口没有任何方法,它是一个标识接口,我们必须以

    void afterThrowing(Methid method,Onject[] args,Object target,Throwable);

    这么定义异常的抛出,方法名必须是afterThrowing,前两个参数可选要么都填,要么都不填,最后Throwable参数必须添加,并且是Throwable或它的子类。

  4. 引介增强(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,代表静态方法。


切点类型

  1. 静态方法切点(org.springframework.aop.support.StaticMethodMatcherPointcut):默认匹配所有的类,有两个子类NameMethodPointcut:(简单的根据字符串进行匹配)和AbstractRegexpMethodPointcut(正则表达式进行匹配)
  2. 动态方法切点(org.springframework.aop.support.DynamicMethodMatcherPointcut):默认匹配所有类,
  3. 流程切点(org.springframework.aop.support.ControlFlowPointcut):它的实现类表示控制流程切点,
  4. 复合切点(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...
0 0
原创粉丝点击