CGLib动态代理
使用JDK动态代理有一个限制,即它只能为接口创建代理实例,这一点可以从接口的newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)的第二个参数看出,interfaces就是需要代理实例实现的接口。对于没有通过接口定义的类,用CGLib技术动态创建代理实例。
用一句简单的话说明这俩的区别:JDK生成的代理类和代理对象实现了同一个接口,CGLib生成的代理类是原代理对象的一个子类(所以被代理的类不能是final的,final不能有子类)。
对于SpringAOP的理解,我们还是要从基本的定义开始:SpringAOP通过Pointcut(切点)指定哪些类的哪些方法上织入横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体切入点(方法前、方法后、方法两端)。Spring通过Advisor(切面)将Pointcut和Advice两者组装起来(再次印证切面就是切点+横切逻辑)。有了Advisor的信息,Spring就可以利用JDK和CGLib的动态代理技术采用统一的方式为目标Bean创建代理对象了。
增强的类型:前置增强、后置增强、环绕增强、异常抛出增强、引介增强。
前置增强的一个例子(一个手写实现接口,一个通过Spring的配置文件):
写一个接口和实现类:
1 //服务员接口 2 package module2.service; 3 4 public interface Waiter { 5 6 public void greetTo(String name); 7 8 public void serveTo(String name); 9 10 } 11 //餐馆服务员接口 12 package module2.service.Impl; 13 14 import module2.service.Waiter; 15 16 public class RestWaiter implements Waiter{ 17 18 public void greetTo(String name){ 19 System.out.println("---greet to "+name+"---"); 20 } 21 22 public void serveTo(String name){ 23 System.out.println("---serving to "+name+"---"); 24 } 25 26 }
写一个增强(横切逻辑):
//横切逻辑 package module2.zq; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class GreetBeforeAdvice implements MethodBeforeAdvice { //实现接口的方法。 public void before(Method method,Object[] args,Object obj) throws Throwable{ //在目标方法调用前执行。 String clientName = (String)args[0]; System.out.println("---How are you ! Mr."+clientName+"---(横切逻辑)"); } }
测试代码和结果:
public static void main(String[] args) { Waiter target = new RestWaiter();//目标对象。 BeforeAdvice advice = new GreetBeforeAdvice();//增强(横切逻辑)。 //Spring提供的代理工厂 ProxyFactory pf = new ProxyFactory(); //设置代理目标 pf.setTarget(target); //为代理目标添加增强 pf.addAdvice(advice); //生成代理实例 Waiter proxyWaiter = (Waiter)pf.getProxy(); proxyWaiter.greetTo("abao"); proxyWaiter.serveTo("binge"); } ========================================== ---How are you ! Mr.abao---(横切逻辑) ---greet to abao--- ---How are you ! Mr.binge---(横切逻辑) ---serving to binge---
在Spring配置中实现上面例子中的代理。
配置文件:
<bean id="greetAdvice" class="module2.zq.GreetBeforeAdvice"/> <bean id="target" class="module2.service.Impl.RestWaiter"/> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="module2.service.Waiter" p:interceptorNames="greetAdvice" p:target-ref="target" />
测试代码:
String configPath = "beans.xml"; ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath); Waiter waiter = (Waiter)ctx.getBean("waiter"); waiter.greetTo("bingee");
代码看着很简单,但是大道至简,那些复杂的功能和抽象的概念都始于此!