Java动态代理使用小记

代理的优点

代理是一种很重要的思想,了解代理的使用对我们的coding很有帮助。使用代理的一些优点:

  • 可以做共性的逻辑处理,比如鉴权、日志、事务等等,实际上这也是AOP的作用
  • 屏蔽网络差异和复杂性,代理在本地,而实际对象(服务)在其他服务器上,调用本地代理时,由本地代理请求其他服务器(如Dubbo的网络调用)

动态代理的方式

1.JDK动态代理

创建方式:

public interface IServiceFoo {
    void sayHello();
}

public class ServiceFooImpl implements IServiceFoo {

    @Override
    public void sayHello() {
        System.out.println("action: ServiceFooImpl.sayHello");
    }
}

/**
 * java.lang.reflect.InvocationHandler
 */
public class SimpleInvocationHandler implements InvocationHandler {

	//被代理的真正的目标对象
    private Object realObj;

    public SimpleInvocationHandler(Object realObj) {
        this.realObj = realObj;
    }

    /**
     * 
     * @param proxy 代理
     * @param method 要调用的方法
     * @param args 方法的参数
     * @return 方法执行结果
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("entering " + method.getDeclaringClass().getSimpleName() + ":: " + method.getName());
        Object result = method.invoke(this.realObj, args);
        System.out.println("leaving " + method.getDeclaringClass().getSimpleName()+":: " + method.getName());

        return result;
    }
}

public class TestA {

    public static void main(String[] args) {
        IServiceFoo realService = new ServiceFooImpl();
        IServiceFoo proxyInstance = getProxy(IServiceFoo.class, realService);
        proxyInstance.sayHello();
    }

    /**
     * 
     * @param targetInterface 被代理的接口
     * @param realObject 被代理的接口的实现
     * @param <T> type
     * @return
     */
    private static <T> T getProxy(Class<T> targetInterface, T realObject) {
        return (T) Proxy.newProxyInstance(targetInterface.getClassLoader(),//类加载器
                new Class[] {targetInterface},//被代理的接口数组
                new SimpleInvocationHandler(realObject));//调用处理器
    }
}

JDK动态代理就是使用Java的反射包java.lang.reflect提供的相关API去实现即可:
Proxy/InvocationHandler

1.cglib动态代理

jdk动态代理的局限在于,它只能为接口创建代理,返回的代理对象也只能转换到某个接口类型,如果要代理类,我们需要使用cglib动态代理。创建方式如下:

/**
 * import org.springframework.cglib.proxy.Enhancer;
 * import org.springframework.cglib.proxy.MethodInterceptor;
 * import org.springframework.cglib.proxy.MethodProxy;
 *
 * import java.lang.reflect.Method;
 *
 */
public class DemoTest {

    static class FooService {
        public final void testMethod() {
            System.out.println("FooService.testMethod action");
        }
    }

    
    static class SimpleInterceptor implements MethodInterceptor {

        /**
         * 
         * @param proxy 代理
         * @param method 要调用的方法
         * @param args 方法参数
         * @param methodProxy 方法代理
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("entering " + method.getDeclaringClass().getSimpleName() + "::" + method.getName());
            //调用超类的方法:即调用被代理的类的方法
            Object result = methodProxy.invokeSuper(proxy, args);
            System.out.println("leaving " + method.getDeclaringClass().getSimpleName() + "::" + method.getName());
            return result;
        }
    }

    /**
     * 
     * @param targetClass 目标类(被代理的类)
     * @param <T> 目标类类型
     * @return
     */
    private static <T> T getProxy(Class<T> targetClass) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetClass);
        enhancer.setCallback(new SimpleInterceptor());
        enhancer.setUseCache(true);
        return (T) enhancer.create();
    }

    public static void main(String[] args) {
        FooService proxy = getProxy(FooService.class);
        proxy.testMethod();
    }
}

cglib的实现机制与java不同,它是通过继承实现的,它也是动态创建了一个类,
但这个类的父类是被代理的类,代理类重写了父类的所有public非final方法
并且目标类方法的调用改为调用Callback中的相关方法,如上述code,调用SimpleInterceptor的intercept方法。

cglib动态代理注意事项,被代理类中定义的final方法可以被调用但是不会走代理逻辑,因为final方法无法被子类(代理类)重写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值