Java实现AOP的两种方式

知道Spring的都知道Spring的切面编程AOP(Aspect Oriented Programming),这里我们不讲Spring的切面,后面有机会我们再来解剖Spring的切面编程,我们想讲解一下普通的Java代码中怎么实现AOP,有两种方式实现AOP切面,一种是原生SDK实现,一种是基于三方包cglib。
先介绍一下JDK原生的,JDK原生的是基于接口编程:
先定义一个接口:

public interface ISayHelloWorld {
    public String say();
}

实现这个接口:

public class ManSayHelloWorld implements ISayHelloWorld{
    @Override
    public String say() {
        System.out.println("Hello world!");
        return "MAN";
    }
}

实现ManSayHelloWorld的切面代理,原生的AOP需要实现InvocationHandler接口,才能实现AOP。

public class AOPHandle implements InvocationHandler{
    private Object obj;
    AOPHandle(Object obj){
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //方法返回值
        System.out.println("前置代理");
        //反射调用方法
        Object ret=method.invoke(obj, args);
        //声明结束
        System.out.println("后置代理");
        //返回反射调用方法的返回值
        return ret;
    }
}

测试这个代码:

public class Main {
    public static void main(String[] args) {
        ManSayHelloWorld sayHelloWorld = new ManSayHelloWorld();
        AOPHandle handle = new AOPHandle(sayHelloWorld);
        ISayHelloWorld i = (ISayHelloWorld) Proxy.newProxyInstance(ManSayHelloWorld.class.getClassLoader(), new Class[] { ISayHelloWorld.class }, handle);
        i.say();
    }
}

执行结果:

前置代理
Hello world! 
后置代理

接下来我们实现一个机遇cglib的切面,实现功能和上面一样,cglib不需要定义接口,普通的类就可以:

public class SayHello {
    public void say(){
        System.out.println("hello world!");
    }
}

实现切面:

public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    public Object getProxy(Class clazz){
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("前置代理");
        //通过代理类调用父类中的方法
        Object result = methodProxy.invokeSuper(o, objects);

        System.out.println("后置代理");
        return result;
    }
}

测试代码:

public class Main {
    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        //通过生成子类的方式创建代理类
        SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);
        proxyImp.say();
    }
}

执行结果:

前置代理
hello world!
后置代理

那么这两种方式有什么相同点和区别呢?
相同点是都使用了代理模式。
不同点是前者使用了接口代理,后者使用了继承代理,什么意思呢?
接口代理:
代理会生成一个类,这个类继承这个接口,并且代理要切面的类,比如上面的例子,AOPHandle会生成一个类,姑且类名叫AspectSayHelloWorld implements ISayHelloWorld,实现say方法时实际上是调用了ManSayHelloWorld的say方法,只是在调用前和调用后做了一些事情而已。
看一下newProxyInstance方法的源码,就知道了:

Objects.requireNonNull(h);

        final Class[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }

继承代理:
继承代理是生成一个代理类,这个类继承于我们需要切面的类,比如上面的 SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);这段代码就返回了SayHello的一个子类,代理了SayHello的say()方法,并且在这个方法前后做了一些事情。

你可能感兴趣的:(Spring系列)