java AOP 的实现方式
札记    无    2016-11-11 15:21:33    374    0    0

总体来说,要实现面向切面编程这个功能,在 java 中有两种方法。

  1. 基于接口实现。
  2. 基于类的继承。

简单建立一个服务类用来测试

public interface Service {
    void create();<!--more-->
    void query();
    void update();
    void delete();
}</pre>

</pre>

public class ServiceBean implements Service{
    public void create(){
        System.out.println("create() is running !");
    }
    public void query(){
        System.out.println("query() is running !");
    }
    public void update(){
        System.out.println("update() is running !");
    }
    public void delete(){
        System.out.println("delete() is running !");
    }
    public final void testFinalMethod(){
        System.out.println("i am final");
    }
    public static void testStaticMethod(){
        System.out.println("i am static");
    }
}</pre></pre>




/**
 * 测试类
 */
public class Client {

    public static void useInteface(){
        Service service = new ServiceBean();
        service.create();
        service.query();
        service.update();
        service.delete();
    }

    public static void main(String[] args) {
         //useInteface()</pre>
        //useInterfacePorxy();</pre>
         //useSubClassProxy();
    }
}
</pre>

基于接口实现

先看 java 标准库自己提供的动态代理方式,这是基于接口的。要被代理的类必须实现某个接口,而且能够被代理的方法就是接口中的方法。

package me.gpio.footprint4j.aop.interfaceproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * Created by Cheney on 2016/11/11.
 */
public class ProxyHandler implements InvocationHandler
{
    private Object proxied;

    public ProxyHandler( Object proxied )
    {
        this.proxied = proxied;
    }

    public Object invoke(Object proxy, Method method, Object[] args ) throws Throwable
    {
        System.out.println("calling method : " + method.getName());

        //在转调具体目标对象之前,可以执行一些功能处理
        System.out.println("before method call");
        //转调具体目标对象的方法
        Object ret = method.invoke( proxied, args);
        //在转调具体目标对象之后,可以执行一些功能处理
        System.out.println("after method call");

        return ret;
    }
}</pre>

然后就可以创建代理类给接口

public static void useInterfacePorxy(){
    Service proxyedService = (Service) java.lang.reflect.Proxy.newProxyInstance(
            ServiceBean.class.getClassLoader(),
            new Class[]{Service.class},
            new me.gpio.footprint4j.aop.interfaceproxy.ProxyHandler(new ServiceBean()));

    proxyedService.create();
    proxyedService.query();
    proxyedService.update();
    proxyedService.delete();

}</pre>

基于类的继承

cglib 提供的代理方式是基于类的继承的,不需要实现某个特定的接口,可以拦截所有方法的调用。但是由于 final 方法不能被继承,所以也不能被代理。

package me.gpio.footprint4j.aop.subclassproxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.apache.log4j.Logger;

import java.lang.reflect.Method;

/**
 * Created by Cheney on 2016/11/11.
 */
public class Proxy implements MethodInterceptor {
    private Logger log= Logger.getLogger(Proxy.class);
    public Enhancer enhancer = new Enhancer();


    public <T> T proxy(Class cls) {
        enhancer.setSuperclass(cls);
        enhancer.setCallback(this);
        return (T)enhancer.create();
    }

    @Override
    public Object intercept(Object object, Method method, Object[] args,
                            MethodProxy methodProxy) throws Throwable {
        log.info("调用的方法是:" + method.getName());
        //用户进行判断
        log.info("before method call");
        Object result = methodProxy.invokeSuper(object, args);
        log.info("after method call");

        return result;
    }

}
</pre>

然后就能创建包装后的类,不需要赋值给接口,静态方法和 final 方法也能调用,只是没有 aop 效果。

public static void useSubClassProxy(){
    Proxy proxy = new Proxy();
    ServiceBean service = proxy.proxy(ServiceBean.class);
    service.create();
    service.query();
    service.update();
    service.delete();
    service.testFinalMethod();
    service.testStaticMethod();

}</pre>
文档导航