Spring    AOP2

来源:互联网 发布:win10 企业版激活软件 编辑:程序博客网 时间:2024/06/02 05:34
Introductions
.允许一个切面声明一个实现指定接口的通知对象,并且提供了一个接口实现类来代表这些对象
.有《aop:aspect》中的《aop:declare-parents》元素声明,该元素用于声明所匹配的类型拥有一个新的parent


《aop:declare-parentstypes-matching="com.imooc.aop.schema.advice.biz.*(+)" 
implement-interface="com.imooc.aop.schema.advice.Fit"default-impl="com.imooc.aop.schema.advice.FitImpl"/》 

public interface Fit {
void filter();

}

public class FitImpl implements Fit {

@Override
public void filter() {
System.out.println("FitImpl filter.");
}

}

@Test
public void testFit() {
Fit fit = (Fit)super.getBean("aspectBiz");
fit.filter();
}

结果:
FitImpl filter.
这里的aspectBiz找到了com.imooc.aop.schema.advice.biz中的指定类,这里的声明的接口Fit来代表这个对象



Advisors
.advisor就像一个小的自包含的方面,只有一个advice
.切面自身通过一个bean表示,并且必须实现某个advice接口,同时,advisor也可以很好的利用AspectJ的切入点表达式
.Spring通过配置文件中《aop:advisor》元素支持advisor实际使用中,大多数情况下它会和transactionaladvice配合使用
.为了定义一个advisor的优先级以便让advice可以有序,可以使用order属性来定义advisor的顺序


spring-aop-schema-advisors.xml:
《beans》
《context:component-scanbase-package="com.imooc.aop.schema"》《/context:component-scan》

《aop:config》
《aop:aspectid="concurrentOperationRetry"ref="concurrentOperationExecutor"》
《aop:pointcut id="idempotentOperation" 
expression="execution(*com.imooc.aop.schema.advisors.service.*.*(..)) " /》
《aop:around pointcut-ref="idempotentOperation"method="doConcurrentOperation" /》
《/aop:aspect》
《/aop:config》
《bean id="concurrentOperationExecutor"class="com.imooc.aop.schema.advisors.ConcurrentOperationExecutor"》
《property name="maxRetries" value="3" /》
《property name="order" value="100" /》
《/bean》
 《/beans》


ConcurrentOperationExecutor:
public class ConcurrentOperationExecutor implements Ordered{

private static final int DEFAULT_MAX_RETRIES = 2;

private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;

public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}

public int getOrder() {
return this.order;
}

public void setOrder(int order) {
this.order = order;
}

public Object doConcurrentOperation(ProceedingJoinPoint pjp)throws Throwable {
int numAttempts = 0;
PessimisticLockingFailureException lockFailureException;
do {
numAttempts++;
System.out.println("Try times : " + numAttempts);
try {
return pjp.proceed();
} catch (PessimisticLockingFailureException ex) {
lockFailureException = ex;
}
} while (numAttempts 《= this.maxRetries);
System.out.println("Try error : " + numAttempts);
throw lockFailureException;
}
}

InvokeService:
@Service
public class InvokeService {
public void invoke() {
System.out.println("InvokeService ......");
}
public void invokeException() {
throw new PessimisticLockingFailureException("");
}

}



@RunWith(BlockJUnit4ClassRunner.class)
public class TestAOPSchemaAdvisors extends UnitTestBase{
public TestAOPSchemaAdvisors() {
super("classpath:spring-aop-schema-advisors.xml");
}
@Test
public void testSave() {
InvokeService service = super.getBean("invokeService");
service.invoke();
System.out.println();
service.invokeException();
  }

}
结果:
Try times : 1
InvokeService ......

Try times : 1
Try times : 2
Try times : 3
Try times : 4
Try error : 4



Spring AOP API
.这是Spring1.2历史用法,现在(V4.0)仍然支持
.这是SpringAOP基础,不得不了解
.现在的用法也是基于历史的,只是更简便了


Pointcut
.实现之一:NameMatchMethodPointcut,根据方法名字进行匹配
.成员变量:mappedNames,匹配的方法名集合

spring-aop-api.xml:
《bean id="bizLogicImplTarget"class="com.imooc.aop.api.BizLogicImpl"》《/bean》 

  《bean id="pointcutBean"class="org.springframework.aop.support.NameMatchMethodPointcut"》 
  《propertyname="mappedNames"》 
《list》 
  《value》sa*《/value》 
  《/list》 
  《/property》 
  《/bean》 

public interface BizLogic {
String save();

}

public class BizLogicImpl implements BizLogic {
public String save() {
System.out.println("BizLogicImpl : BizLogicImpl save.");
return "BizLogicImpl save.";
// throw new RuntimeException();
}

}
这里以及下面的操作先不进行测试,到后面在进行测试。


Before advice
.一个简单的通知类型
.只是在进入方法之前被调用,不需要MethodInvocation对象
.前置通知可以在连接点执行之前自定义行为,但不能改变返回值
public class MoocBeforeAdvice implements MethodBeforeAdvice{

@Override
public void before(Method method, Object[] args, Objecttarget)
throws Throwable {
System.out.println("MoocBeforeAdvice : " + method.getName() +"     " + 
target.getClass().getName());
}

}


Throws advice
.如果连接点抛出异常,throws advice在连接点返回后被调用
.如果throws-advice的方法抛出异常,那么他将覆盖原有异常
.接口org.springframework.aop.ThrowsAdvice不包含任何方法,仅仅是一个声明,实现类需要实现类似下面的方法:
.voidafterThrowing([Method,args,target],ThrowableSubclass);

public class MoocThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(Exception ex) throws Throwable{
System.out.println("MoocThrowsAdvice afterThrowing 1");
}
public void afterThrowing(Method method, Object[] args, Objecttarget, Exception ex) throws Throwable {
System.out.println("MoocThrowsAdvice afterThrowing 2 : " +method.getName() + "      " + 
target.getClass().getName());
}

}

After Returning advice
.后置通知必须实现org.springframework.aop.AfterReturningAdvice接口
.可以访问返回值(但不能进行修改),被调用的方法,方法的参数和方法
.如果抛出异常,将会抛出拦截器链,代替返回值

public class MoocAfterReturningAdvice implementsAfterReturningAdvice {

@Override
public void afterReturning(Object returnValue, Methodmethod,
Object[] args, Object target) throws Throwable {
System.out.println("MoocAfterReturningAdvice : " +method.getName() + "     "+ 
target.getClass().getName() + "      " + returnValue);
}

}


Interception around advice
.Spring的切入点模型使得切入点可以独立与advice重用,以针对不同的advice可以使用相同的切入点
public class MoocMethodInterceptor implementsMethodInterceptor {

@Override
public Object invoke(MethodInvocation invocation) throwsThrowable {
System.out.println("MoocMethodInterceptor 1 : " +invocation.getMethod().getName() + "    " + 
invocation.getStaticPart().getClass().getName());
Object obj = invocation.proceed();
System.out.println("MoocMethodInterceptor 2 : " + obj);
return obj;
}

}


Introduction advice
.Spring把引入通知作为一种特殊的拦截通知
.需要IntroductionAdvisor和IntroductionInterceptor
.仅适用于类,不能和任何切入点一起使用
.一个Spring test suite的例子
.如果调用lock()方法,希望所有的setter方法抛出LockedException异常(如使物体不可变,AOP典型例子)
.需要一个完成繁重任务的IntroductionInterceptor,这种情况下,可以使用org.springframework.aop.support.DelegatingIntorductionInterceptor

public interface Lockable {
void lock();

void unlock();

boolean locked();

}

public class LockMixin extendsDelegatingIntroductionInterceptor implements Lockable {

private static final long serialVersionUID =6943163819932660450L;
private boolean locked;

    public void lock(){
       this.locked = true;
    }

    public void unlock(){
       this.locked = false;
    }

    public boolean locked(){
       return this.locked;
    }

    public Objectinvoke(MethodInvocation invocation) throws Throwable {
       if (locked() &&invocation.getMethod().getName().indexOf("set") == 0) {
           throw newRuntimeException();
       }
       return super.invoke(invocation);
    }

}

public class LockMixinAdvisor extendsDefaultIntroductionAdvisor {

private static final long serialVersionUID =-171332350782163120L;

public LockMixinAdvisor() {
       super(new LockMixin(), Lockable.class);
    }
}



Advisor API in Spring
.Advisor是仅包含一个切入点表达式关联的单个通知的方面
.除了introductions,advisor可以用于任何通知
.org.springframework.aop.support.DefaultPointcutAdvisor是最常用的advisor类,它可以与MethodInterceptor,BeforeAdvice或者ThroesAdvice一起使用
.它可以混合在Spring同一个送票代理的advisor和advice



ProxyFactoryBean
.创建SpringAOP代理的基本方法是使用org.springfromework.aop.framework.ProxyFactoryBean
.这可以完全控制切入点和通知以及他们的顺序
.使用ProxyFactoryBean创建的一个对象foo并不是ProxyFactoryBean实例,而是:
Spring <wbr> <wbr> <wbr> <wbr>AOP2

.使用ProxyFactoryBean或者其他IoC相关类来创建AOP代理的最重要的好处就是通知和切入点也可以由IoC来管理
.被代理类没有实现任何接口,使用CGLIB代理,否则JDK代理
.通过设置ProxyTargetClass为true,可以强制使用CGLIB
.如果目标类实现了一个(或多个)接口,那么创建代理的类型将依赖ProxyFactoryBean的配置
.如果ProxyFactoryBean的proxyInterfaces属性被设置为一个或多个全限定接口名,基于JDK的代理将被创建
.如果ProxyFactoryBean的proxyInterfaces没有被设置,但目标类实现了一个或更多接口那么ProxyFactoryBean将自动检测到这个目标类已经实现了至少一个接口,创建一个基于JDK的代理
Spring <wbr> <wbr> <wbr> <wbr>AOP2




这里就可以来测试上面所诉的一些代码:
需要先修改xml文件:
《bean id="moocAfterReturningAdvice"class="com.imooc.aop.api.MoocAfterReturningAdvice"》《/bean》
《bean id="moocMethodInterceptor"class="com.imooc.aop.api.MoocMethodInterceptor"》《/bean》
《bean id="moocThrowsAdvice"class="com.imooc.aop.api.MoocThrowsAdvice"》《/bean》

《bean id="bizLogicImplTarget"class="com.imooc.aop.api.BizLogicImpl"》《/bean》

《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="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》moocAfterReturningAdvice《/value》
《value》moocMethodInterceptor《/value》
《value》moocThrowsAdvice《/value》
《/list》
《/property》
《/bean》

执行结果:
MoocBeforeAdvice : save    com.imooc.aop.api.BizLogicImpl
MoocMethodInterceptor 1 : save    java.lang.reflect.Method
BizLogicImpl : BizLogicImpl save.
MoocMethodInterceptor 2 : BizLogicImpl save.
MoocAfterReturningAdvice : save    com.imooc.aop.api.BizLogicImpl     BizLogicImpl save.


修改:
public class BizLogicImpl implements BizLogic {
public String save() {
System.out.println("BizLogicImpl : BizLogicImpl save.");
//return "BizLogicImpl save.";
throw new RuntimeException();
}

}

结果:
MoocBeforeAdvice : save    com.imooc.aop.api.BizLogicImpl
MoocMethodInterceptor 1 : save    java.lang.reflect.Method
BizLogicImpl : BizLogicImpl save.
MoocThrowsAdvice afterThrowing 2 : save     com.imooc.aop.api.BizLogicImpl

如果将sa*(sava方法)改为sq*,结果中将不会出现beforeadvice。




上述是使用pointcutbean方式进行的更精确的操作,如果不实用pointcutbean的话:
《bean id="bizLogicImplTarget"class="com.imooc.aop.api.BizLogicImpl"》《/bean》

《bean id="bizLogicImpl"class="org.springframework.aop.framework.ProxyFactoryBean"》
《property name="proxyInterfaces"》
《value》com.imooc.aop.api.BizLogic《/value》
《/property》
《property name="target"》
《ref bean="bizLogicImplTarget" /》
《/property》
《property name="interceptorNames"》
《list》
moocBeforeAdvice
《value》moocAfterReturningAdvice《/value》
《value》moocMethodInterceptor《/value》
《value》moocThrowsAdvice《/value》
《value》mooc*《/value》
《/list》
《/property》
《/bean》
这里面自定了接口name="proxyInterfaces"。

执行结果无论是否抛出异常都和上面的一致。






.使用匿名内部bean来隐藏目标和代理之间的区别
删除《beanid="bizLogicImplTarget"class="com.imooc.aop.api.BizLogicImpl"》《/bean》
更改:
《property name="target"》
《bean class="com.imooc.aop.api.BizLogicImpl"》《/bean》
《/property》

结果一致。推荐的用法是第二种方式,第一种方式的备案可以直接通过其id访问到,这样的话,后面的通知和接口就不会被访问到。






Proxying classes
.前面的例子中没有Person接口,这种情况下spring会使用CGLIB代理,而不是JDK动态代理
.如果想,可以强制在任何情况下使用CGLIB,即使有接口
.CGLIB代理的工作原理是在运行时生成目标类的子类,Spring配置这个生成的子类委托方法调用到原来的目标
.子类是用来实现Decorator模式,织入通知
.CGLIB的代理对用户是透明的,需要注意:
 - final方法不能被通知,因为他们不能被覆盖
 -不用把CGLIB添加到classpath中,在Spring3.2中,CGLIB被重新包装并包含在Spring核心的JAR(即基于CGLIB的AOP就像JDK动态代理一样"开箱即用")





使用global advisor
.用*做通配,匹配所有拦截器加入通知链
《property name="interceptorNames"》
《list》
《value》mooc*《/value》
《/list》
《/property》

结果:
MoocMethodInterceptor 1 : save    java.lang.reflect.Method
BizLogicImpl : BizLogicImpl save.
MoocMethodInterceptor 2 : BizLogicImpl save.

这里只运行了MoocMethodInterceptor,因为只有他继承了MethodInterceptor(拦截器)



简化的proxy定义
.使用父子bean定义,以及内部bean定义,可能会带来更清洁和更简洁的代理定义(抽象属性标记父bean定义为抽象的这样它不会被实例化)
《bean id="baseProxyBean"class="org.springframework.aop.framework.ProxyFactoryBean"
lazy-init="true" abstract="true"》《/bean》
《bean id="bizLogicImpl" parent="baseProxyBean"》
《property name="target"》
《bean class="com.imooc.aop.api.BizLogicImpl"》《/bean》
《/property》
《property name="proxyInterfaces"》
《value》com.imooc.aop.api.BizLogic《/value》
《/property》
《property name="interceptorNames"》
《list》
moocBeforeAdvice
《value》moocAfterReturningAdvice《/value》
《value》moocMethodInterceptor《/value》
《value》moocThrowsAdvice《/value》
《/list》
《/property》
《/bean》


结果一致。





使用ProxyFactory
.使用Spring AOP而不必依赖于Spring IoC
ProxyFactory factory = newProxyFactory(myBusinessInterfaceImpl)
factory.addAdvice(myMethodInterceptor);
factory.addAdvisor(myAdvisor);
MyBusinessInterface tb = (MyBussinessInterface)factory.getProxy();
.大多数情况下最佳实践使用IoC容器创建AOP代理
.虽然可以硬编码方式实现,但是Spring推荐使用配置或注解方式实现




使用"auto-proxy"
.Spring也允许使用自动代理的bean定义,他可以在动代理选定的bean,这是建立在spring的bean postprocessor 功能基础上(在加载bean的时候就可以修改)
.BeanNameAutoProxyCreator
img
.DefaultAdvisorAutoProxyCreator,当前IoC容器中自动应用,不用显示声明引用Advisor的bean定义
Spring <wbr> <wbr> <wbr> <wbr>AOP2

0 0
原创粉丝点击