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 具体实现的细节, 如你有兴趣可翻翻源码, 这里就不赘述了.
至此代理的几种方式已经使用都已描述完毕, 如有不符, 还望斧正.
来源: https://www.cnblogs.com/java-class/p/10455094.html