Java实现AOP的方式

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方法的源码,就知道了:

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException{
    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<Void>() {
                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()方法,并且在这个方法前后做了一些事情。

你可能感兴趣的:(AOP)