好久没有动笔了, 最近想巩固一下自己的基础知识, 最近听到一同事问为什么 JDK 动态代理不能代理类, 一听感觉懵逼呀! 自己好像也不能很好的描述出来, 所以想用 2 篇文章来复习一下动态代理知识;
一, 什么是静态代理? 什么是动态代理?
静态代理:
静态代理是在写代码中就把各个代理关系给理清了, 在编译期就确定了类之间的关系;
动态代理:
在程序运行期间根据需要动态的创建代理类及其实例, 来完成具体的功能;
二, 为什么要使用代理?
兄弟, 你打方法的出入参的代码可以推一个房子了吧. 使用代理可以将代码解耦, 很多时候我们只要去关注我们最核心的实现, 一些其他方面我可以交给代理去实现. 最好的说明就是我们日常的 AOP 日志了, 就是靠代理实现的.
三, 简单的代理实现
静态代理的简单实现代码参考我前面的代理模式的代码:
今天我们先要写一下动态代理的简单代码:
InvocationHandler
InvocationHandler 是 JDK 中提供的专门用于实现基于接口的动态代理的接口, 主要用于进行方法调用模块, 而代理类和实例的生成需要借助 Proxy 类完成. 每个代理类的实例的调用处理器都是实现该接口实现的, 而且是必备的, 即每个动态代理实例的实现都必须拥有实现该接口的调用处理器, 也可以这么说, 每个动态代理实例都对应一个调用处理器. 这里要区分两个概念, 代理类和代理实例, 调用处理器是在创建代理实例的时候才与其关联起来的, 所以它与代理实例是一一对应的, 而不是代理类.
Proxy
Proxy 类是 JDK 提供的用于生成动态代理类和其实例的类. 我们可以通过 Proxy 中的静态方法 getProxyClass 来生成代理类, 需要的参数为类加载器和接口列表 (数组), 然后再通过反射调用代理类的构造器来生成代理实例, 需要以一个 InvocationHandler 作为参数 (体现出方法调用是与实例相关的, 而非类).
了解了上面我们开始写代码实现:
先写一个接口 UserService, 里面包含一个根据 id 查询用户名的方法, 我们在这个查询方法的前后打印出出入参
- package com.roc.study.proxy;
- /**
- * <code > 用户 service</code>
- * <b>Note</b>
- *
- * @author liaowp
- * @see
- * @since 2018/5/14
- */
- public interface UserService {
- /**
- * 查询用户名称
- * @param id
- * @return
- */
- String getUserName(Integer id);
- }
- package com.roc.study.proxy;
- /**
- * <code > 用户 service 实现类 </code>
- * <b>Note</b>
- *
- * @author liaowp
- * @see
- * @since 2018/5/14
- */
- public class UserServiceImpl implements UserService {
- /**
- * 查询用户名称
- *
- * @return
- */
- @Override
- public String getUserName(Integer id) {
- System.out.println("liaowp");
- return "liaowp";
- }
- }
- package com.roc.study.proxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- /**
- * <code > 用户代理类 </code>
- * <b>Note</b>
- *
- * @author liaowp
- * @see
- * @since 2018/5/14
- */
- public class UserInvocationHandler implements InvocationHandler {
- private Object target;
- public UserInvocationHandler(Object target) {
- this.target = target;
- }
- /**
- * 在代理实例上处理方法调用并返回结果.
- * 当在与其关联的代理实例上调用方法时, 将在调用处理程序上调用此方法.
- * @param proxy 我们所代理的那个真实对象
- * @param method 方法
- * @param args 入参
- * @return
- * @throws Throwable
- */
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- System.out.println("入参 args->" + args);
- // 执行目标对象的方法
- Object result = method.invoke(target, args);
- System.out.println("出参 args->"+result.toString());
- return result;
- }
- /**
- * 获取目标对象的代理对象
- * @return 代理对象
- */
- public Object getProxy() {
- return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
- target.getClass().getInterfaces(), this);
- }
- }
- package com.roc.study.proxy;
- /**
- * <code > 代理测试类 </code>
- * <b>Note</b>
- *
- * @author liaowp
- * @see
- * @since 2018/5/14
- */
- public class ProxyTest {
- public static void main(String[] args) {
- UserService userService = new UserServiceImpl();
- UserInvocationHandler userInvocationHandler = new UserInvocationHandler(userService);
- // 根据目标对象生成代理对象
- UserService proxy = (UserService) userInvocationHandler.getProxy();
- // 调用代理对象的方法
- proxy.getUserName(1);
- }
- }
运行结果:
入参 args->[Ljava.lang.Object;@5cad8086
liaowp
出参 args->liaowp
Process finished with exit code 0
来源: https://www.cnblogs.com/liaoweipeng/p/9038030.html