什么是代理模式

代理模式主要对我们方法执行之前与之后实现增强

代理模式应用场景

  1. 日志的采集
  2. 权限控制
  3. 实现aop
  4. Mybatis mapper
  5. Spring的事务
  6. 全局捕获异常
  7. Rpc远程调用接口
  8. 代理数据源

代理模式实现的原理

代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy),如上图所示:

一文看懂代理模式

 

 

抽象主题角色:可以是接口,也可以是抽象类;

委托类角色:真实主题角色,业务逻辑的具体执行者;

代理类角色:内部含有对真实对象RealSubject的引用,负责对真实主题角色的调用,并在真实主题角色处理前后做预处理和后处理。

代理模式创建方式

静态代理

静态代理需要自己人工编写代理类代码

基于接口实现方式

public class OrderServiceProxy  implements  OrderService{
    private OrderService orderService;

    public OrderServiceProxy(OrderService orderService) {
        this.orderService = orderService;
    }

    public String addOrder(String userName, String userPwd) {
        System.out.println("使用静态代理类打印日志开始:userName:" + userName + "," + userPwd);
        String result = orderService.addOrder(userName, userPwd);
        System.out.println("使用静态代理类打印日志结束:userName:" + userName + "," + userPwd);
        return result;
    }
}

 

 

public interface OrderService {
    /**
     * 需要被代理的方法
     * @return
     */
     String addOrder(String userName,String userPwd);
}

 

 

public class Test001 {
    public static void main(String[] args) {
        OrderService orderService = new OrderServiceProxy(new OrderServiceImpl());
        orderService.addOrder("mayikt","123456");
    }
}

 

 

基于继承的实现方式

public class OrderServiceProxy  extends OrderServiceImpl {
    private OrderService orderService;

    public OrderServiceProxy(OrderService orderService) {
        this.orderService = orderService;
    }

    public String addOrder(String userName, String userPwd) {
        System.out.println("使用静态代理类打印日志开始:userName:" + userName + "," + userPwd);
        String result = super.addOrder(userName, userPwd);
        System.out.println("使用静态代理类打印日志结束:userName:" + userName + "," + userPwd);
        return result;
    }
}

 

 

动态代理与静态代理的区别

 

动态代理不需要写代理类对象,通过程序自动生成,而静态代理需要我们自己写代理类对象。

 

动态代理

动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。

动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成 。

 

Jdk动态代理

JDK动态代理的一般步骤如下:

1.创建被代理的接口和类;

2.实现InvocationHandler接口,对目标接口中声明的所有方法进行统一处理;

3.调用Proxy的静态方法,创建代理类并生成相应的代理对象;

实现原理:利用拦截器机制必须实现InvocationHandler接口中的invoke方法实现对

我们的目标方法增强。

public class JdkInvocationHandler implements InvocationHandler {
    /**
     * 目标对象
     */
    private Object target;

    public JdkInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     * @param proxy  使用jdk程序生成的代理类
     * @param method 目标方法
     * @param args 方法需要传递的参数
     * @return
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("使用Jdk动态代理打印日志开始" + args[0]);
        Object result = method.invoke(target, args);
        System.out.println("使用Jdk动态代理打印日志结束" + args[1]);
        return result;
    }

    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

}

 

JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(new OrderServiceImpl());
OrderServiceImpl orderService = jdkInvocationHandler.getProxy();
orderService.addOrder("mayikt", "meite");

 

加上该代码:

 

  1. 获取代理的生成的class文件

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")

 

一文看懂代理模式

 

 

CGLIB动态代理

利用asm字节码技术,生成子类实现对目标方法实现增强

实现方式

Maven依赖

<dependencies>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.2.12</version>
    </dependency>
</dependencies>

 

 

核心代码

public class CglibMethodInterceptor implements MethodInterceptor {
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("<<<<<日志收集开始...>>>>>>>");
        Object reuslt = proxy.invokeSuper(obj, args);
        System.out.println("<<<<<日志收集结束...>>>>>>>");
        return reuslt;
    }
}

 

 

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
CglibMethodInterceptor cglibMethodInterceptor = new CglibMethodInterceptor();
Enhancer enhancer = new Enhancer();
// 设置代理类的付类
enhancer.setSuperclass(MemberServiceImpl.class);
// 设置回调对象
enhancer.setCallback(cglibMethodInterceptor);
// 创建代理对象
MemberServiceImpl orderServiceImpl = (MemberServiceImpl) enhancer.create();
orderServiceImpl.getMember();

 

 

 

 

Jdk与Cglib动态代理的区别

  1. Jdk动态代理利用反射技术生成匿名的代理类走InvokeHandler回调方法实现增强,同时也是一种基于接口的方式实现代理。
  2. Cglib动态代理利用asm字节码技术生成一个子类覆盖其中的方法实现增强,同时采用fastClass机制对整个代理类建立索引比反射效率要高
  3. 在Spring中如果需要被代理的对象如果实现了接口采用Jdk动态代理,没有实现接口则使用Cglib动态代理。

 

相关文章:

  • 2021-12-18
  • 2021-08-20
  • 2021-09-06
  • 2021-09-27
  • 2021-08-27
  • 2021-07-20
  • 2021-08-12
  • 2022-12-23
猜你喜欢
  • 2021-09-11
  • 2021-08-15
  • 2022-12-23
  • 2021-10-30
  • 2022-01-07
  • 2023-02-06
  • 2021-12-30
相关资源
相似解决方案