AOP浅析
发表于|更新于
|字数总计:1k|阅读时长:4分钟|阅读量:
aop 是现代web框架底层核心技术之一,很多人能熟练运用 @aspect
@joinpoint
去实现业务代码,但未必明白 aop 的来龙去脉。考虑这样一个say()
:
public class Hello0 { public void say(){ System.out.println("hello"); } }
|
如果想在say()
前后执行一些增强代码,该怎么做呢?
实现方案一
小A采用了下面的写法。很不幸,小A这段代码写完后,就被辞退了。
public class Hello0plus { private Hello0 hello0;
public Hello0plus() { this.hello0 = new Hello0(); }
public void say(){ before(); hello0.say(); after(); } private void before(){ System.out.println("before"); } private void after(){ System.out.println("after"); } }
|
实现方案二
小B这个时候想起了代理模式,使用代理模式重构了代码:
public interface Hello { void say(); } public class HelloImpl implements Hello{ @Override public void say() { System.out.println("hello"); } } public class HelloProxy implements Hello{ private Hello hello;
public HelloProxy() { this.hello = new HelloImpl(); }
@Override public void say() { before(); hello.say(); after(); }
private void before(){ System.out.println("before"); } private void after(){ System.out.println("after"); } }
|
学以致用,小B很兴奋,大量使用了这种代理方式,XXXProxy
满天飞。架构师看到项目里的代码目瞪口呆,冲小B咆哮到:你就不会动态代理吗?赶紧给我重构!
实现方案三
小B查阅了资料,终于搞明白动态代理是啥,动态代理是利用Java 6 引入的InvocationHandler
接口的实现。主要涉及到两个类:
java.lang.reflect Proxy
,主要方法为
static Object newProxyInstance(ClassLoader loader, //指定当前目标对象使用类加载器
Class<?>[] interfaces, //目标对象实现的接口的类型 InvocationHandler h //事件处理器 )
|
java.lang.reflect InvocationHandler
,主要方法为
Object invoke(Object proxy, Method method, Object[] args)
|
小B弄明白后兴奋的重写了代码:
public class HelloProxyPlus implements InvocationHandler { private Object target;
public HelloProxyPlus(Object target) { this.target = target; }
@Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { before(); Object result = method.invoke(target,objects); after(); return result; }
private void before(){ System.out.println("before"); } private void after(){ System.out.println("after"); } }
|
在使用的时候:
Hello helloImpl = new HelloImpl(); HelloProxyPlus helloProxyPlus = new HelloProxyPlus(helloImpl); Hello dynamicHello = (Hello)Proxy.newProxyInstance(helloImpl.getClass().getClassLoader(),helloImpl.getClass().getInterfaces(),helloProxyPlus); dynamicHello.say();
|
这种方式能将一个增强方法运用到所有的欲增强类中。大大精简了项目代码。
实现方案四
小B的兴奋劲没过几天,又遇到了难题。Proxy.newProxyInstance
的第二个参数是getInterfaces()
,只能代理接口方法。但并不是所有需要增强的方法都是接口方法呀。小B没招了,去请教架构师,架构师给了他一个建议,为什么不用cglib呢?小B如获至宝,查阅资料后才明白cglib
是一个代码生成库,能在运行时动态生成一个类的子类,在生成过程中提供了callback
织入自定义代码。小B搞明白后改写了代码:
public class HelloProxyPlusPlus implements MethodInterceptor {
@Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { before(); Object result = methodProxy.invokeSuper(o,objects); after(); return result; }
private void before(){ System.out.println("before"); } private void after(){ System.out.println("after"); } }
|
在使用的时候:
HelloProxyPlusPlus helloProxyPlusPlus = new HelloProxyPlusPlus(); Hello cglibHello = (Hello)Enhancer.create(HelloImpl.class,helloProxyPlusPlus); cglibHello.say();
|
Enhancer.create()
接受两个参数:第一个参数是需要继承的父类,第二个参数是MethodInterceptor
对象,在MethodInterceptor
对象的intercept
中实现对父类方法的增强。
小B志得意满了,等着评审会好好秀一下。
END
终于到了开会的日子,架构师看完了小B的代码,向小B建议到:为什么不用注解去指明要代理谁,在生成子类后用子类的实例替换掉父类的实例呢?这样就能让被代理的方法和使用者都毫无感知了。
是的,这就是 spring 的 aop 。