在说起动态代理前先说明一下静态代理模式,静态代理模式是一种很常见的通用设计模式,实现也很简单,uml类图以下:html
如上图所示,代理类ProxyImpl和委托类都实现了同一个接口ObjectInterface,代理类和委托类是关联关系。
举个栗子,如今有一个发送短信消息的类SmsMessagePush,实现了MessagePushjava
public interface MessagePush { public void push(String receiver, String msg); }
public class SmsMessagePush implements MessagePush { @Override public void push(String receiver, String msg) { //do push } }
通常状况下,用户直接调用SmsMessage.push()便可,为何要用代理呢?通常有两种状况
1:用户没法直接访问目标对象(委托对象)或者是不想让用户直接访问目标对象,这时候proxy对象就承担了一种相似跳板机或者防火墙的角色,代替用户访问目标对象或者对访问者的权限进行筛选。
2:对委托对象的功能加强,好比上面的例子,在发送短信前添加对手机号码进行校验之类的功能。spring
public class SmsMessagePushProxy implements MessagePush { private SmsMessagePush smsMessagePush; public SmsMessagePushProxy(SmsMessagePush smsMessagePush) { this.smsMessagePush = smsMessagePush; } @Override public void push(String mobile, String msg) { if (!checkMobile(mobile)){ return; } smsMessagePush.push(mobile, msg); } private Boolean checkMobile(String mobile) { //do check } }
public class App { public static void main() { SmsMessagePushProxy smsMessagePushProxy = new SmsMessagePushProxy(new SmsMessagePush()); smsMessagePushProxy.push("10086", "老子明天不上班"); } }
上面的代理SmsMessagePushProxy在调用push方法前会对手机号码进行过滤。代理类做为中介提供了对委托资源的访问,可是代理和委托对象本质上是同样的,都实现了同一个接口,因此当接口变化时代理类就须要对应的修改。并且没增长一个委托类就须要增长一个对应的代理类,管理起来十分不方便且难以维护。为了解决这种状况,便引入了jdk动态代理。express
静态代理是在编码阶段就写好的,而动态代理是在程序运行时经过类反射动态建立的。java的动态代理分为jdk动态代理和cglib动态代理,两者使用上最大的区别是jdk动态代理是面向接口的,cglib动态代理是面向对象的。即jdk proxy的委托对象必须实现了某个接口。这里暂不讨论cglib的实现,只讲下jdk。编程
动态代理主要涉及的类放在java.lang.reflect包下面(因而可知是基于反射实现的),主要涉及两个类:调用处理器java.lang.reflect.InvocationHandle和主类java.lang.reflect.Proxy
其中InvocationHandler是一个接口,只定义了一个方法json
public Object invoke(Object proxy, Method method, Object[] args)
从参数名就能够猜想,invoke方法是用来执行委托对象的具体方法的
Proxy类有不少静态方法,最经常使用的一个方法是newProxyInstance,该方法会根据传入的参数建立一个代理对象设计模式
@CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
该方法接受三个参数,第一个参数指定要使用的类加载器,第二个参数是委托对象实现的一组接口。第三个参数指定使用哪一个调用处理器。
第二个参数我开始还纠结为何是个接口数组,难道一个代理实例能够代理多个实现了不一样接口的委托对象?在invoke方法中也区分不了当前要执行的是哪一个对象啊,并且这样两个接口有相同名称的方法会产生冲突啊。。。后来发现大多数状况下是由于委托对象实现了多个接口。。。
下面举个栗子:
假设有一个类PushServiceImpl实现了SmsPushInterface和MailPushInterface两个接口数组
public class PushServiceImpl implements SmsPushInterface, MailPushInterface { @Override public void pushEmail(String address, String msg) { System.out.println("push a email to " + address + ",message is " + msg); } @Override public void pushSms(String mobile, String msg) { System.out.println("push a sms to " + mobile + ",message is " + msg); } } public interface SmsPushInterface { public void pushSms(String mobile, String msg); } public interface MailPushInterface { public void pushEmail(String address, String msg); }
如今想要对PushServiceImpl对象进行代理,定义一个getProxy方法,方法接收一个委托对象做为参数,返回的类型是Object,实际上返回的是一个代理对象,该代理对象实现了SmsPushInterface和MailPushInterface两个接口。代理对象经过Proxy.newProxyInstance()
方法建立。springboot
public class ProxyTest { public Object getProxy(Object target) throws Exception { InvocationHandler handler = new PushHandler(target); return Proxy.newProxyInstance( ProxyTest.class.getClassLoader(), target.getClass().getInterfaces(), handler ); } @Test public void proxyTest() throws Exception { SmsPushInterface smsPushService = (SmsPushInterface) getProxy(new PushServiceImpl()); smsPushService.pushSms("10086", "这一切都是命运石之门的选择"); MailPushInterface mailPushService = (MailPushInterface) getProxy(new PushServiceImpl()); mailPushService.pushEmail("31415926@qq.com", "都是时臣的错"); } }
因为获取代理类返回的是Object类型,在实际使用时要根据调用的方法转换成对应的接口类型,注意这里不能转成PushServiceImpl即实例对象的类型,由于返回的代理类是Proxy的子类,实现了这两个接口而已。
在调用代理类的方法时,其实是执行处理器在运行,以下所示,咱们编写一个PushHandler实现InvocationHandler接口并覆写invoke方法:app
public class PushHandler implements InvocationHandler { private Object proxied; PushHandler(Object proxied) { this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("pushSms".equals(method.getName())) { String mobile = args[0].toString(); String msg = args[1].toString(); if (!checkMobile(mobile)) { throw new Exception("mobile invalid"); } } if ("pushEmail".equals(method.getName())) { String address = args[0].toString(); String msg = args[1].toString(); if (!checkMail(address)) { throw new Exception("mail address invalid"); } } return method.invoke(proxied, args); } private Boolean checkMobile(String mobile) { // check mobile valid return true; } private Boolean checkMail(String mailAddress) { // check mail valid return true; } }
PushHandler在构造方法中接受一个委托对象实例,最后实际执行的就是这个对象的方法。在执行getProxy返回的代理对象的方法时会调用PushHandler的invoke方法,其中proxy参数就是当前的代理对象(java.lang.reflect.Proxy的子类),method是当前执行方法,args是参数数组。在这个例子里咱们根据方法名来作对应的检查以后经过反射方法method.invoke()执行。
具体的动态代理运行原理这里暂不展开,网上有不少相关的内容,好比这篇
http://blog.jobbole.com/104433
aop(Aspect Oriented Programming) 翻译过来就是面向方面/切面编程。关于aop的定义有许多,这里引用一个可能不是特别准确但很容易理解的解释:(出处www.zhihu.com/question/24863332/answer/253016908)
aop是一种思想而不是一种技术。因此说,若是抛开spring,我上面写的动态代理甚至静态代理的例子也能够算是一种aop。
spring中的aop实现分为两种,基于动态代理的aop和基于AspectJ的aop,这里不得不吐槽国内的各类文章,根本没搞清两者的区别,或者打着spring aop的标题而后开始讲aspectJ的使用,你抄我我抄他,越抄越混乱。
在网上一搜一大片所谓AspectJ的用法,其实都是AspectJ的“切面语法”,只是AspectJ框架的冰山一角,AspectJ是彻底独立于Spring存在的一个Eclipse发起的项目,官方关于AspectJ的描述是:
Eclipse AspectJ is a seamless aspect-oriented extension to the Java™ programming language. It is Java platform compatible easy to learn and use.
是的AspectJ甚至能够说是一门独立的语言,咱们常看到的在spring中用的@Aspect注解只不过是Spring2.0之后使用了AspectJ的风格而已本质上仍是Spring的原生实现,关于这点Spring的手册中有说起:
@AspectJ使用了Java 5的注解,能够将切面声明为普通的Java类。@AspectJ样式在AspectJ 5发布的AspectJ project部分中被引入。Spring 2.0使用了和AspectJ 5同样的注解,并使用AspectJ来作切入点解析和匹配。可是,AOP在运行时仍旧是
纯的Spring AOP
,并不依赖于AspectJ的编译器或者织入器(weaver)。
so 咱们经常使用的org.aspectj.lang.annotation包下的AspectJ相关注解只是使用了AspectJ的样式,至于全套的AspectJ以及织入器,那彻底是另外一套独立的东西。
在看aop实现前,先解释几个基本名词,对就是网上一搜一大片那些
advice
advice,常被翻译成”加强“或者”通知“,实际上advice就是在切面中执行的额外操做,拿上面动态代理的例子来讲在PushHandler::invoke()方法中,对手机号码以及邮箱地址的检查就是两个advice。在不少aop框架中advice是以拦截器的形式存在的,advice又常分为前置型advice和后置型advice,像手机号码检查这种就属于前置的advice,返回结果记录日志就属于后置advice
join point
链接点很容易理解,先看下spring手册上的定义
a· point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution.
join point 就是程序运行时的一个特征点,好比方法的执行或者异常的抛出。能够把join point理解为一个触发条件。
point cut
point cut大部分状况下被翻译为’切入点‘。不少人常常搞不清楚join point 和 point cut的区别,实际上两者彻底不是一个维度的概念,若是说join point是名词 point cut就是谓词。pointcut是一个规则,指定了哪些切入点会被切入。
好比:在test.network.message包下全部类的push()方法执行前,对入参作校验
其中push()就是一个join point , 在xx前,对入参进行验证是一个advice,而”在test.network.message包下全部类的push()方法“就是一个point cut。
作个比喻的话,一个插排,每一个插孔都是一个join point,而电视插在哪,电脑插在哪,整个一个布线规则就是一个point cutaspect
在test.network.message包下全部类的push()方法执行前,对入参作校验
整个这个行为就是一个切面了。因此切面能够理解为point cut和advice的集合。在使用AspectJ样式时,被@Aspect注解标注的类就是一个切面。
为防止翻译不统一形成的误解,下面对名词的使用直接使用英文原文
spring aop常被人诟病复杂,难用。但又有多少新司机真正的用过而不是上来就被@Aspectj那一套洗脑了,问你为何spring aop难用,AspectJ的优点在哪又有多少人能答上来。
spring aop相关的内容基本都在org.springframework.aop.framework包下,spring aop是经过代理工厂实现的,主要涉及的类图以下:
两个经常使用的aop工厂类ProxyFactoryBean和ProxyFactoryBean继承自ProxyCreatorSupport,proxyCreator是代理类的基类,并拥有一个实现了AopProxyFactory接口的属性DefaultAopProxyFactory,ProxyFactory中的getProxy方法实际上最后是调用的是AopProxy接口中的getProxy方法,而实现了AopProxy接口的对象(JdkDynamicAopProxy或CglibAopProxy)是由DefaultAopProxyFactory建立的。这么说可能会有点绕,下面用一张时序图来解释(图是我偷的,懒得画了,出处:https://www.jianshu.com/p/500...)
DefaultAopProxyFactory在建立aop代理时会判断委托类是否实现了某个接口,是的话建立JdkDynamicAopProxy,不然的话建立ObjenesisCglibAopProxy,代码以下:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } }
下面看一个使用proxyFactory实现aop的例子
public class SpringAopTest { @Test public void proxy() { PushServiceImpl pushService = new PushServiceImpl(); //建立工厂 ProxyFactory proxyFactory = new ProxyFactory(pushService); //添加advice proxyFactory.addAdvice(new SmsPushBeforeAdvice()); proxyFactory.addAdvice(new SmsPushAfterAdvice()); //获取代理 SmsPushInterface proxy = (SmsPushInterface) proxyFactory.getProxy(); proxy.pushSms("10086", "EL PSY CONGROO"); } }
public class SmsPushBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { if ("pushSms".equals(method.getName())) { String mobile = args[0].toString(); String msg = args[1].toString(); if (!checkMobile(mobile)) { throw new Exception("mobile invalid"); } } } private Boolean checkMobile(String mobile) { //do mobile check System.out.println("check mobile valid"); return true; } }
public class SmsPushAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { StringBuffer logData = new StringBuffer(); logData.append("get method return : method:" + method.getName()); logData.append(" message : \"" + args[1] + "\"was sent"); if (returnValue == null) { logData.append(" and return value is void"); } addLog(logData.toString()); } private void addLog(String logMsg) { //do log System.out.println("get log info: " + logMsg); } }
下面是测试运行时的输出:
check mobile valid push a sms to 10086,message is EL PSY CONGROO get log info: get method return : method:pushSms message : "EL PSY CONGROO"was sent and return value is void
能够看到,使用proxyFactory实现aop和上面的动态代理的例子十分类似 ,spring aop中的advice就等同于咱们在动态代理中InvocationHandler中的加强操做。
经常使用的advice有四种:
前置advice:在方法执行前触发的advice,实现了 org.springframework.aop.MethodBeforeAdvice接口
后置advice: 在方法返回时触发的advice,实现了org.springframework.aop.AfterReturningAdvice接口
异常advice:在抛出异常后触发,实现了org.springframework.aop.ThrowsAdviceArround
环绕advice:自定义触发时机,实现和InvokeHandler相似,实现了org.aopaliance.intercept.MethodInterceptor
advisor:
上面的例子,添加的advice在实际运行时会包装为Advisor对象,advisor包含了advice和pointcut,能够理解为一个切面(aspect),下面是AdvisedSupport类的addAdvice的方法实现,能够看到在执行addAdvice方法时会封装为DefaultPointcutAdvisor实例
public void addAdvice(int pos, Advice advice) throws AopConfigException { Assert.notNull(advice, "Advice must not be null"); if (advice instanceof IntroductionInfo) { // We don't need an IntroductionAdvisor for this kind of introduction: // It's fully self-describing. addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice)); } else if (advice instanceof DynamicIntroductionAdvice) { // We need an IntroductionAdvisor for this kind of introduction. throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor"); } else { addAdvisor(pos, new DefaultPointcutAdvisor(advice)); } }
在DefaultPointcutAdvisor中,pointCut被默认设置为Poincut.TRUE,此时会匹配被代理对象的全部方法
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable { private Pointcut pointcut = Pointcut.TRUE;
除了直接设置advice之外,咱们还能够设置advisor,并指定对应的pointcut,这样就能够指定哪些方法会被切入,pointcut和advisor有许多包装类型,都在org.springframework.aop.support
包下,这里使用最经常使用的正则pointcut:JdkRegexpMethodPointcut
举个栗子
public void pointTest() { SmsPushInterface pushService = new PushServiceImpl(); //建立工厂 ProxyFactory proxyFactory = new ProxyFactory(pushService); //建立advisor并添加advice DefaultPointcutAdvisor beforeAdvisor = new DefaultPointcutAdvisor(new SmsPushBeforeAdvice()); DefaultPointcutAdvisor afterAdvisor = new DefaultPointcutAdvisor(new SmsPushAfterAdvice()); //建立正则方法pointcut JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut(); //设置正则规则 pointcut.setPattern(PushServiceImpl.class.getName() + ".push.*"); beforeAdvisor.setPointcut(pointcut); afterAdvisor.setPointcut(pointcut); //设置advisor proxyFactory.addAdvisor(beforeAdvisor); proxyFactory.addAdvisor(afterAdvisor); //获取代理 SmsPushInterface proxy = (SmsPushInterface) proxyFactory.getProxy(); proxy.pushSms("10086", "EL PSY CONGROO"); }
能够看到此次咱们没有直接使用addAdvice而是建立了两个advisor,并建立了一个pointcut,设置正则pattern匹配全部以push开头的方法。
这里有一个坑,我开始在设置pattern时是直接写成 setPattern("push.*")的,发现没有匹配,后来发现AbstractRegexpMethodPointcut的matches方法里是这样写的
public boolean matches(Method method, Class<?> targetClass) { return ((targetClass != null && matchesPattern(ClassUtils.getQualifiedMethodName(method, targetClass))) || matchesPattern(ClassUtils.getQualifiedMethodName(method))); }
ClassUtils.getQualifiedMethodName
方法会将method名称拼上类名,即要匹配的方法名其实是 spring.aop.PushServiceImpl.pushSms
在使用时咱们会发现这样手动设置pointcut和advisor十分麻烦,因此spring aop提供了一些包装好的advisor,好比上面的这个正则的例子咱们就能够直接使用org.springframework.aop.supportRegexpMethodPointcutAdvisor
,还有一些更方便的包装advisor好比下面这个例子直接使用了NameMatchMethodPointcutAdvisor设置匹配的方法名
@Test public void proxy() { PushServiceImpl pushService = new PushServiceImpl(); //建立工厂 ProxyFactory proxyFactory = new ProxyFactory(pushService); //建立方法名称匹配advisor并添加advice NameMatchMethodPointcutAdvisor beforeAdvisor = new NameMatchMethodPointcutAdvisor(new SmsPushBeforeAdvice()); NameMatchMethodPointcutAdvisor afterAdvisor = new NameMatchMethodPointcutAdvisor(new SmsPushAfterAdvice()); //设置匹配的方法名 beforeAdvisor.setMappedName("pushSms"); afterAdvisor.setMappedName("pushSms"); //设置advisor proxyFactory.addAdvisor(beforeAdvisor); proxyFactory.addAdvisor(afterAdvisor); //获取代理 SmsPushInterface proxy = (SmsPushInterface) proxyFactory.getProxy(); proxy.pushSms("10086", "EL PSY CONGROO"); }
以上就是SpringAop的基本使用方法,经过上面的例子能够看出springAop的确存在一些问题,最明显的就是切面不够独立,对业务代码的侵入性很强,声明Aspect须要以过程的形式显示声明(虽然ProxyFactoryBean能够将切面部分封装为bean,可是我看到xml是在是想吐)。并且advice和pointcut的结合灵活性较差,实际使用时还须要本身写一些轮子。spring也认识到了这些问题并在spring2.0以后推出了AspectJ样式的Aop
再次强调一下这里讲的AspectJ样式的aop只是使用了AspectJ的一些语法特性,底层依旧是SpringAop实现的
首先 使用aspectJ样式的aop须要一些额外配置
@EnableAspectJAutoProxy
注解来开启,另外若是你使用了@EnableAutoConfiguration
会默认开启。若是想关闭aop能够配置设置spring.aop.auto = false
,spring.aop.proxy-target-class
能够指定使用jdk代理仍是cglib代理,默认是jdk(false:jdk,true:cglib)<aop:aspectj-autoproxy proxy-target-class="false"/>
来开启,设置为true使用cglib前面springAop已经将aop的概念说的很清楚这里就不扯淡了直接上个例子:
@Aspect注解将当前类标记为一个切面,@Component将PushAspect注册为Bean
@Pointcut注解将一个void方法标记为一个pointcut,execution、within、args等被称为pointcut designators(切点标志符)简称为PCD,每一个PCD都有对应的表达式,好比最经常使用的execution,下面的例子第一个表示修饰符,即public仍是private之类。后面紧接着是包名+类名+方法名,spring.aop.PushServiceImpl.* 表示匹配 spring.aop包下PushServiceImpl类的全部方法。最后是参数标识(String,Stirng)表示参数是两个String类型的方法,若要匹配全部参数类型,可使用(..)表示
@Aspect @Component public class PushAspect { @Pointcut(value = "execution(* spring.aop.PushServiceImpl.pushSms(String,String))") public void pushSmsPointcut() { } @Pointcut("execution(* spring.aop.PushServiceImpl.*(..))") public void pushMethodPointcut() { } @Before("pushSmsPointcut() && args(mobile,msg)") public void checkMobile(String mobile, String msg) throws Exception { if (!checkMobile(mobile)) { throw new Exception("mobile invalid"); } } private Boolean checkMobile(String mobile) { //do mobile check System.out.println("check mobile valid"); return true; } @AfterReturning(pointcut = "pushMethodPointcut()", returning = "returnValue") public void writeLog(JoinPoint joinPoint, Object returnValue) { StringBuffer logData = new StringBuffer(); logData.append("get method return : method:" + joinPoint.getSignature().getName()); logData.append(" message : \"" + joinPoint.getArgs()[1].toString() + "\"was sent"); if (returnValue == null) { logData.append(" and return value is void"); } addLog(logData.toString()); } private void addLog(String logMsg) { //do log System.out.println("get log info: " + logMsg); } }
@Before、@AfterReturn、@Around等注解标识了一个advice方法,advice和pointcut相关联,像上面这个例子前置advice checkMobile()就是做用于被pushSmsPointcut标识的方法上,pointcut能够显示绑定在value或pointcut参数上,或者不写参数默认第一表达式就是pointcut。也能够不写pointcut,在advice表达式内直接写PCD,可是不建议这样作
关于怎么向advice body里传递参数,先看下手册里的描述:
To make argument values available to the advice body, you can use the binding form of args. If a parameter name is used in place of a type name in an args expression, then the value of the corresponding argument will be passed as the parameter value when the advice is invoked
因此想要传递参数在advcie中使用args表达式便可,注意这里要在args里写参数名,而不是写参数类型。写参数类型的话是另外一种用法,通常写在PCD中,做为joinpoint匹配时参数类型的筛选。另外传递的参数中还有一个特别的参数类型JoinPoint. jointpoint包含了不少实用的反射方法,必须获取当前的代理类,获取参数列表等等,joinpoint能够做为第一个参数传入advice且不用再参数列表里指定。这里注意使用around advice时传入的是ProceedingJoinPoint类型的jointpoint
execution表达式中的参数和args
在designator表达式中,有两种方式能够限定方法的参数,一个是经过execution表达式的最后一个参数,另外一个是经过args标识符,两者有什么区别?
args(java.lang.String) execution(* *(java.lang.String))
区别是args表达式标识的是在运行时传入的参数是String类型,而execution表达式表示的是方法签名在定义的时候是String。
Aspectj风格还有不少designators(with,@annotation等),以及advice类型,这里再也不赘述,能够参考spring的手册。虽然是英文的但写的很详细
手册: https://docs.spring.io/spring...
下面是委托对象的执行(实际上不该该再叫他委托对象了,由于这里已经将aop剥离出来了,用户感知不到代理的过程)。能够看到和IOC结合起来十分方便,切面和业务代码没有任何耦合。这里若是把注入的SmsPushInterface换成SmsBean named 'pushServiceImpl' is expected to be of type 'spring.aop.PushServiceImpl' but was actually of type 'com.sun.proxy.$Proxy61'
.能够看出底层的实现仍是使用的动态代理,若是这里想声明Impl类型能够把代理改为cglib.
@RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) public class SpringAopTest { @Resource SmsPushInterface pushService; @Test public void aspectjTest() throws Exception { pushService.pushSms("10086", "EL PSY CONGROO"); }
上面的例子都是在IOC环境中自动加载的,若是脱离这个环境想在过程当中执行怎么办?spring提供了一个org.springframework.aop.aspectj.annotation.AspectJProxyFactory 代理工厂,和ProxyFactory同样继承ProxyCreatorSupport,经过该工厂能够像proxyFactory同样直接显示进行代理
@Test public void testAspectJProxyFactory() { PushServiceImpl pushService = new PushServiceImpl(); AspectJProxyFactory proxyFactory = new AspectJProxyFactory(pushService); proxyFactory.addAspect(PushAspect.class); SmsPushInterface proxy = (SmsPushInterface) proxyFactory.getProxy(); proxy.pushSms("10086", "EL PSY CONGROO"); }
从下面的源码能够看出,这里addAspect实际上仍是把@Aspect解析成Advisor来处理
public void addAspect(Class<?> aspectClass) { String aspectName = aspectClass.getName(); AspectMetadata am = createAspectMetadata(aspectClass, aspectName); MetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName); addAdvisorsFromAspectInstanceFactory(instanceFactory); }
因而可知,AspectJ样式的方便不仅是体如今提供了一些方便的注解以及PCD,更体如今和Spring IOC的完美结合关于@Aspect的解析原理,是在没时间写了,之后有时间再补吧。写的比较匆忙若有问题欢迎指正