AOP总结(spring)

xiaoxiao2025-02-13  16

实现AOP流程:

Service s = new ServiceImpl(); //创建切入点 Pointcut pc = new JdkRegexpMethodPointcut();//JdkRegexpMethodPointcut是切入点实现类。spring提供7个切入点实现类@1 //创建通知 Advice advice = new SimpleAdvice();//SimpleAdvice实现了通知接口。srping提供5种通知接口@2 //创建通知者 Advisor advisor = new DefaultPointcutAdvisor(pc,advice);//DefaultPointcutAdvisor是通知者实现类。spring提供3个通知者实现类@3 //创建代理 ProxyFactory pf = new ProxyFactory();//spring支持两种代理@4 pf.addAdvisor(advisor); pf.setTarget(s); proxy = (Service)pf.getProxy(); proxy .doSomething();

 

 

 1、七种PointCut实现

Perl5RegexpMethodPointcut 是一个最基本的正则表达式切入点, 它使用Perl 5正则表达式语法。Perl5RegexpMethodPointcut 依赖Jakarta ORO进行正则表达式匹配。

 

JdkRegexpMethodPointcut 类,它使用JDK 1.4或更高版本里提供的正则表达式支持。

 

RegexpMethodPointcutAdvisor , 它也允许我们引用一个通知(记住这里一个通知可以是拦截器,前置通知(before advice),异常通知(throws advice)等类型中的一个)。 在背后,如果使用J2SE 1.4或者以上版本,Spring将使用JdkRegexpMethodPointcut , 在之前版本的虚拟机上,Spring将退回去使用Perl5RegexpMethodPointcut 。 可以通过设置perl5 属性为true来强制使用Perl5RegexpMethodPointcut 。 使用RegexpMethodPointcutAdvisor 可以简化织入,因为一个bean可以同时作为切入点和通知器(advisor),如下所示:

<bean id="settersAndAbsquatulateAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice"> <ref local="beanNameOfAopAllianceInterceptor"/> </property> <property name="patterns"> <list> <value>.*set.*</value> <value>.*absquatulate</value> </list> </property> </bean>

 

 

 

ControlFlowPointcut在运行时控制流切入点的开销是非常昂贵的,甚至与其它动态切入点比起来也是如此。在Java 1.4里, 它的开销差不多是其它动态切入点的5倍。

 

StaticMethodMatcherPointcut

因为静态切入点是最常用的,你可能会像下面那样继承StaticMethodMatcherPointcut。这只需要实现一个抽象方法 (虽然也可以覆盖其它方法来定制行为):

class TestStaticPointcut extends StaticMethodMatcherPointcut { public boolean matches(Method m, Class targetClass) { // return true if custom criteria match } }

 

ComposablePointCut可组合切入点。可通过union()和intersection()等操作组合两个以上的切入点。

 

DynamicMethodMatcherPointcut流程切入点。

 

动态切入和静态切入:

public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher(); } public interface ClassFilter { boolean matches(Class clazz); } public interface MethodMatcher { boolean matches(Method m, Class targetClass); boolean isRuntime(); boolean matches(Method m, Class targetClass, Object[] args); }

 

matches(Method, Class) 方法用来测试这个切入点是否匹配目标类的指定方法。 这将在AOP代理被创建的时候进行运算,这样可以避免在每次方法调用的时候都运算。 如果matches(Method, Class) 对于一个给定的方法返回true,并且isRuntime() 也返回true, 那么matches(Method, Class, Object[]) 将在每个方法调用的时候被调用。 这使得切入点在通知将被执行前可以查看传入到方法的参数。

大多数MethodMatcher是静态的,这意味着isRuntime() 方法返回false。 在这种情况下,matches(Method, Class , Object[]) 永远不会被调用。

如果是静态切入,Spring会针对目标上的每一个方法调用一次matches(Method m, Class targetClass),其返回值被缓冲起来方便日后调用该方法时使用。这样,对每个方法的适用性测试只会进行一次,之后调用该方法时不全再调用matches()。

 

2、五种通知

MethodInterceptor拦截环绕通知

public interface MethodInterceptor extends Interceptor { Object invoke(MethodInvocation invocation) throws Throwable; }

 

 

BeforeAdvice 前置通知

public interface MethodBeforeAdvice extends BeforeAdvice { void before(Method m, Object[] args, Object target) throws Throwable; }

 

 

 

AfterReturningAdvice 后置通知

public interface AfterReturningAdvice extends Advice { void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable; }

 

ThrowsAdvice异常通知

public interface ThrowsAdviceextends AfterAdvice{ afterThrowing([Method, args, target], subclassOfThrowable) }

 

 IntroductionInterceptor 引入通知

public interface IntroductionInterceptor extends MethodInterceptor { boolean implementsInterface(Class intf); }

 

 调用的方法位于一个已经被引入接口里,这个引入拦截器将负责完成对这个方法的调用--因为它不能调用proceed() 方法。引入通知不能和任何切入点一起使用,因为它是应用在类级别而不是方法级别。 你只能通过

IntroductionAdvisor来使用引入通知,这个接口包括下面的方法:

public interface IntroductionAdvisor extends Advisor, IntroductionInfo { ClassFilter getClassFilter(); void validateInterfaces() throws IllegalArgumentException; } public interface IntroductionInfo { Class[] getInterfaces(); }

 

 

这里没有MethodMatcher 接口,因此也就没有 Pointcut 与引入通知相关联。这里只进行类过滤。

getInterfaces() 方法返回这个通知器所引入的接口。

validateInterfaces() 方法将被内部使用来查看被引入的接口是否能够由配置的IntroductionInterceptor 来实现。

 3、三个通知者类

DefaultPointcutAdvisor 

在Spring里,一个Advisor是一个仅仅包含一个通知对象和与之关联的切入点表达式的切面。

除了引入这种特殊形式,任何通知器(advisor)都可以和任何通知一起工作。 org.springframework.aop.support.DefaultPointcutAdvisor 是最常用的通知器类。例如,它可以和 MethodInterceptor ,BeforeAdvice 或者 ThrowsAdvice 一起使用。

在Spring里有可能在同一个AOP代理里混合通知器和通知类型。 例如,你可以在一个代理配置里使用一个拦截环绕通知,一个异常通知和一个前置通知:Spring将负责自动创建所需的拦截器链。

RegexpMethodPointcutAdvisor

StaticMethodMatcherPointcutAdvisor 

4.1、三个代理实现类

BeanNameAutoProxyCreator为名字匹配字符串或者通配符的bean自动创建AOP代理。

 

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <value>jdk*,onlyJdk</value> </property> <property name="interceptorNames"> <list> <value>myInterceptor</value> </list> </property> </bean>

 

DefaultAdvisorAutoProxyCreator

它自动应用当前上下文中适当的通知器,无需在自动代理通知器的bean定义中包括bean的名字。 比起BeanNameAutoProxyCreator ,它提供了同样关于一致性配置的优点而避免了前者的重复性。

使用这个功能将涉及:

Specifying a DefaultAdvisorAutoProxyCreator bean definition.

说明一个 DefaultAdvisorAutoProxyCreator 的bean定义

在同一个或者相关的上下文中说明任意数量的通知器。注意这些必须 是通知器而不仅仅是拦截器或者其它通知。 这点是必要的因为必须有一个切入点被评估,以便检查每个通知候选bean定义的合适性。

DefaultAdvisorAutoProxyCreator 将自动评估包括在每个通知器中的切入点,

 

 

AbstractAdvisorAutoProxyCreator

这是DefaultAdvisorAutoProxyCreator的父类。如果在某些情况下框架提供的DefaultAdvisorAutoProxyCreator 不能满足你的需要,你可以通过继承这个类来创建你自己的自动代理创建器。

 

4.2、两种代理支持

JKD动态代理

java.lang.reflect.Proxy.getProxyClass(loader, interfaces). getConstructor(new Class[] { InvocationHandler.class }). newInstance(new Object[] { handler });

 CGLIB基于ASM框架生成字节码

1、首次创建CGLIB代理时,CGLIB会询问Spring每个方法应该如何处理。这意味着很多决定在JDK代理中每次invoke()调用时都要进行,但在CGLIB中只需要进行一次。CGLIB可以直接调用未被通知的方法,但JDK动态代理要去判断。

2、对于固定通知链的通知,CGLIB可以优化执行。

3、CGLIB对于被代理的方法,也使用了生成字节码的能力,执行被代理方法效率比JDK代理略微高。

 

转载请注明原文地址: https://www.6miu.com/read-5024642.html

最新回复(0)