继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Java 基础【19】代理

HUWWW
关注TA
已关注
手记 285
粉丝 37
获赞 133

 Java 代理(Proxy)模式与现实中的代理含义一致,如旅游代理、明星的经纪人。

   在目标对象实现基础上,增加额外的功能操作,由此来扩展目标对象的功能。

   JavaWeb 中最常见的过滤器、Struts 中的拦截器、Spring 中的 AOP...都有代理的应用。

   此篇博客将编写例子描述 Java 底层技术和开源类库Cglib实现代理的方法,并对比各方法的优缺性。

回到顶部

1.JDK 静态代理

   抽象接口:

复制代码

/**
 * 用户服务抽象 */public interface UserService {    /**
     * 用户登录
     *
     * @param userName 用户名
     * @param pwd      密码
     * @return 登陆结果     */
    String login(String userName, String pwd);
}

复制代码

   实现该接口:

复制代码

/**
 * 用户服务实现
 *
 * @author Rambo 2019-03-01
 **/public class UserServiceImpl implements UserService {


    @Override    public String login(String userName, String pwd) {
        Console.log("进行登陆逻辑.........");        return "登陆结果";
    }
}

复制代码

   编码代理类,实现该接口,代理目标作为私有对象:

复制代码

/**
 * 用户服务代理类
 *
 * @author Rambo 2019-03-01
 **/public class UserServiceProxy implements UserService {    private UserService userService;

    UserServiceProxy(UserService userService) {        this.userService = userService;
    }

    @Override    public String login(String userName, String pwd) {
        Console.log("登陆前扩展.....");
        userService.login(userName, pwd);
        Console.log("登陆后扩展.....");        return "登陆结果";
    }
}

复制代码

   编写测试类:

    @Test    public void testLogin() throws Exception {
        UserServiceProxy userServiceProxy = new UserServiceProxy(new UserServiceImpl());
        userServiceProxy.login("rambo","111111");
    }

   这应该是最原始实现代理的样子,缺点也很明显,需要编码代理类,势必导致代理类冗余,且当目标类增加或删除方法时,需要维护代理类。   

回到顶部

2.JDK 动态代理(接口代理)

   代理核心方法 Proxy.newProxyInstance :

复制代码

    /**
     * JDK 生成代理类
     * @param loader 当前目标对象使用类加载器
     * @param interfaces 目标对象实现的接口的类型
     * @param h 事件处理对象,通过反射执行目标对象的方法
     * @return 生成的代理类实例     */
    @CallerSensitive    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

复制代码

   代理工厂类:

复制代码

/**
 * 代理工厂类
 *
 * @author Rambo 2019-03-01
 **/public class JdkProxyFactory {    private Object target;    public JdkProxyFactory(Object target) {        this.target = target;
    }    public Object getProxyInstance() {        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Console.log("执行目标前的扩展......");
                Object returnValue = method.invoke(target, args);
                Console.log("执行目标后的扩展......");                return returnValue;
            }
        });
    }
}

复制代码

   编写测试类:

    @Test    public void testGetProxyInstance() throws Exception {
        UserService proxyInstance = (UserService) new ProxyFactory(new UserServiceImpl()).getProxyInstance();
        proxyInstance.login("rambo", "111111");
    }

   目标对象需要实现接口,代理对象是可以不用实现接口的。

   使用目标对象接口、自定义调用处理类 InvocationHandler 实例化代理类,内部通过反射调用目标对象的方法。

回到顶部

3.Cglib 代理 (子类代理)

   当目标对象是个单独的类,没有实现任何接口,是无法使用上述两种代理方法,这时候怎么办?

   可以使用 Cglib 代理(需要单独引入 cglib 类库),自定义目标类的子类进行目标对象的扩展,且这种扩展进行在 Jvm 运行期。

   Cglib 底层是通过一个小而快的字节码处理框架 Asm 来转换字节码并生成新的类。

   不局限目标类存在方式、运行期增强目标类、底层精致的 asm 字节码框架,使 Cglib 成为许多 AOP 框架生成动态代理的首选。

   代理工厂类:

复制代码

/**
 * Cglib 动态代理工厂
 *
 * @author Rambo 2019-03-01
 **/public class CgbProxyFactory implements MethodInterceptor {    private Object target;    public CgbProxyFactory(Object target) {        this.target = target;
    }    public Object getProxyInstance() {
        Enhancer en = new Enhancer();
        en.setSuperclass(target.getClass());
        en.setCallback(this);        return en.create();

    }

    @Override    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        Console.log("执行目标前的扩展......");
        Object returnValue = method.invoke(target, args);
        Console.log("执行目标后的扩展......");        return returnValue;
    }
}

复制代码

   编写测试用例:

    @Test    public void testGetProxyInstance() throws Exception {
        UserService proxyInstance = (UserService) new CgbProxyFactory(new UserServiceImpl()).getProxyInstance();
        proxyInstance.login("rambo","111111");
    }

   JDK InvocationHandler 、Cglib MethodInterceptor 具体实现的细节,如你有兴趣可翻翻源码,这里就不赘述了。

   至此代理的几种方式已经使用都已描述完毕,如有不符,还望斧正。

 

作者:Orson            
出处:http://www.cnblogs.com/java-class/


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP