写在前面
Spring将introduction通知看作一种特殊类型的拦截通知。用Spring的行话来讲,对方法的增强叫做Wearing(织入),而对类的增强叫introduction(引入)。Introduction Advice(引入增强)就是对类的功能增强,它也是Spring AOP 提供的一种特殊增强。
一个简单的例子(以CGLIB的代理实现)
定义一个接口(这个例子演示了一个mixin。我们想要能够 将被通知对象类型转换为Lockable,不管它们的类型,并且调用lock和unlock方法。如果我们调用 lock()方法,我们希望所有setter方法抛出LockedException异常。 这样我们能添加一个方面使的对象不可变,而它们不需要知道这一点:这是一个很好的AOP例 子。)
public interface Lockable { void lock(); void unlock(); boolean locked(); }
首先,我们需要一个做大量转化的IntroductionInterceptor。 在这里,我们继承 org.springframework.aop.support.DelegatingIntroductionInterceptor 实用类。我们可以直接实现IntroductionInterceptor接口,但是大多数情况下 DelegatingIntroductionInterceptor是最合适的。
这样,LockMixin继承DelegatingIntroductionInterceptor 并自己实现Lockable。父类自动选择支持导入的Lockable,所以我们不需要指定它。 用这种方法我们可以导入任意数量的接口。
public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable { private boolean locked; public void lock() { this.locked = true; } public void unlock() { this.locked = false; } public boolean locked() { return this.locked; } public Object invoke(MethodInvocation invocation) throws Throwable { if (locked() && invocation.getMethod().getName().indexOf("set") == 0) throw new LockedException(); return super.invoke(invocation); } }
通常不要需要改写invoke()方法:实现 DelegatingIntroductionInterceptor就足够了,如果是导入的方法, DelegatingIntroductionInterceptor实现会调用委托方法, 否则继续沿着连接点处理。在现在的情况下,我们需要添加一个检查:在上锁 状态下不能调用setter方法。
在spring中的配置如下
<bean id="aServiceImpl" class="com.xxx.plus.aop.demo.AServiceImpl" /> <bean id="lockAdvice" class="com.xxx.plus.aop.demo.LockMixin" /> <bean id="aServiceImplProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interfaces" value="com.xxx.plus.aop.demo.Lockable" /> <property name="target" ref="aServiceImpl" /> <property name="proxyTargetClass" value="true"></property> <property name="interceptorNames"> <list> <value>lockAdvice</value> </list> </property> </bean>
客户的代码代用如下
ApplicationContext context =new FileSystemXmlApplicationContext( "beans-config.xml"); AService aServiceProxy =(AService) context.getBean("proxyFactoryBean"); // 物件没有被锁定,可以呼叫 set 方法 some.setSome("justin"); System.out.println(some.getSome()); try { // (重点一) ((LockAble) aServiceProxy).lock(); // 无法呼叫 set 方法,丢出例外 aServiceProxy.setSome("momor"); // 由于会丢出例外,所以下面的这行程式无法被执行 System.out.println(aServiceProxy.getSome()); } catch(Throwable e) { e.printStackTrace(); } some.setSome("momor");
System.out.println(aServiceProxy.getSome());
重点一:这里的lock()方法可以直接被aServiceProxy调用,这里将aServiceProxy由AService强转为LockAble 没有报错。原理是在生产代理的时候,代理对象动态的实现了LockAble 接口。
public Object getProxy(ClassLoader classLoader) { ...... Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); //重点1.1(将advised 的接口也给了代理对象,获得完整的代理接口) enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class)); Callback[] callbacks = getCallbacks(rootClass); Class<?>[] types = new Class<?>[callbacks.length]; ....... }
重点1.1(所以上面的强转是不会报错的)
public static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised) {
//获取所有的代理接口 Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces(); if (specifiedInterfaces.length == 0) { // No user-specified interfaces: check whether target class is an interface. Class<?> targetClass = advised.getTargetClass(); if (targetClass != null) { if (targetClass.isInterface()) { advised.setInterfaces(targetClass); } else if (Proxy.isProxyClass(targetClass)) { advised.setInterfaces(targetClass.getInterfaces()); } specifiedInterfaces = advised.getProxiedInterfaces(); } } boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class); boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class); int nonUserIfcCount = 0; if (addSpringProxy) { nonUserIfcCount++; } if (addAdvised) { nonUserIfcCount++; } Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount]; System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length); if (addSpringProxy) { proxiedInterfaces[specifiedInterfaces.length] = SpringProxy.class; } if (addAdvised) { proxiedInterfaces[proxiedInterfaces.length - 1] = Advised.class; } return proxiedInterfaces; }
客户的的代码
aService.barA();
//h会发现这里的强制转换时成功的 Lockable ku = ((Lockable) aService); ku.lock();
输出结果:
AServiceImpl.barA()
is lock
引入增强(JDK 代理实现)
接口与实现类,引入增强类
public interface ISome { public void doSome(); }
public class Some implements ISome { public void doSome() { System.out.println("原来物件的职责。。。"); } }
public class OtherIntroduction extends DelegatingIntroductionInterceptor implements IOther { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { return super.invoke(methodInvocation); } public void doOther() { System.out.println("增加的职责。。。"); } }
配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN/EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="some" class="com.xxx.Some"/> <bean id="otherIntroduction" class="com.xxx.OtherIntroduction"/> <bean id="otherAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor"> <constructor-arg index="0"> <ref bean="otherIntroduction"/> </constructor-arg> <constructor-arg index="1"> <value>onlyfun.caterpillar.IOther</value> </constructor-arg> </bean> <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>com.xxx.ISome</value> </property> <property name="target"> <ref bean="some"/> </property> <property name="interceptorNames"> <list> <value>otherAdvisor</value> </list> </property> </bean> </beans>
测试代码
public static void main(String[] args) { ApplicationContext context = new FileSystemXmlApplicationContext("classpath:beans-config.xml"); ISome some = (ISome) context.getBean("proxyFactoryBean"); some.doSome(); // 看来好像 some 物件动态增加了职责 ((IOther) some).doOther(); }
运行结果
原来物件的职责。。。
增加的职责。。。
分析:JDK 在代理接口的时候动态的代理了增强类实现的接口
@Override public Object getProxy(ClassLoader classLoader) { //重点1 这里获取的所有完整的代理接口 Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }
这里其实和CGLIB 代理是一样的。获取所有的需要代理的接口
public static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised) { Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces(); if (specifiedInterfaces.length == 0) { // No user-specified interfaces: check whether target class is an interface. Class<?> targetClass = advised.getTargetClass(); if (targetClass != null) { if (targetClass.isInterface()) { advised.setInterfaces(targetClass); } else if (Proxy.isProxyClass(targetClass)) { advised.setInterfaces(targetClass.getInterfaces()); } specifiedInterfaces = advised.getProxiedInterfaces(); } } boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class); boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class); int nonUserIfcCount = 0; if (addSpringProxy) { nonUserIfcCount++; } if (addAdvised) { nonUserIfcCount++; } Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount]; System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length); if (addSpringProxy) { proxiedInterfaces[specifiedInterfaces.length] = SpringProxy.class; } if (addAdvised) { proxiedInterfaces[proxiedInterfaces.length - 1] = Advised.class; } return proxiedInterfaces; }
然后动态的实现接口,这样就可以实现强转了