飞道的博客

SpringAop底层原理 Java动态代理思想

434人阅读  评论(0)

java动态代理实现与原理详细分析

关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式–代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理。

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。在后面我会

解释这种间接性带来的好处。代理模式结构图(图片来自《大话设计模式》):

看这个是不是有点费劲,来下面我们来个简单的

通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用处理,或调用后处理。既(AOP微实现) ,AOP核心技术面向切面编程。

代理模式运用场景

SpringAop ,事务原理,日志打印,权限控制,远程调用,安全代理

代理的分类

静态代理(静态定义代理类)
动态代理(动态生成代理类)
Jdk自带动态代理
Cglib 、javaassist(字节码操作库)

什么是静态代理

由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

package com.evan.springboot.designStudy.proxyDemo;

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 10:42
 */
public interface UserService {
    void save();
}


public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        System.out.println("插入用户成功");
    }
}


package com.evan.springboot.designStudy.proxyDemo.st;

import com.evan.springboot.designStudy.proxyDemo.UserService;
import com.evan.springboot.designStudy.proxyDemo.UserServiceImpl;

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 10:45
 */
public class UserProxy implements UserService {
    private UserService userService;

    public UserProxy(UserService userService){
        this.userService=userService;
    }

    @Override
    public void save() {
        System.out.println("开启事务");
        userService.save();
        System.out.println("事务执行");
    }


    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserProxy userProxy = new UserProxy(userService);
        userProxy.save();
    }
}

什么是动态代理

1.代理对象,不需要实现接口
2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
3.动态代理也叫做:JDK代理,接口代理

JDK动态代理

  • 原理:

根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口,面向接口生成代理,位于java.lang.reflect包下)

  • 实现方式
    1,通过实现InvocationHandler接口创建自己的调用处理器UserJDkProxy。
  1. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
  2. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
  3. 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));

缺点:jdk动态代理,必须是面向接口,目标业务类必须实现接口

package com.evan.springboot.designStudy.proxyDemo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 10:57
 */
public class UserJDkProxy implements InvocationHandler {
    private UserService userService;
    public UserJDkProxy(UserService userService){
        this.userService=userService;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("jdk 动态代理开始");
        Object invoke = method.invoke(userService, args);
        System.out.println("Jdk 动态代理结束");
        return invoke;
    }
}

package com.evan.springboot.designStudy.proxyDemo;

import java.lang.reflect.Proxy;

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 11:06
 */
public class Client {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserJDkProxy userJDkProxy = new UserJDkProxy(userService);
        UserService o = (UserService) Proxy.newProxyInstance(userJDkProxy.getClass().getClassLoader(), userService.getClass().getInterfaces(), userJDkProxy);
        o.save();
    }
}

Cglib动态代理

  • 原理:

利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

什么是CGLIB动态代理

使用cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码

package com.evan.springboot.designStudy.proxyDemo;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 11:31
 */
public class UserCglibProxy implements MethodInterceptor {
    private Object object;
    public Object getInstance(Object object){
        this.object=object;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(object.getClass());
        enhancer.setCallback(this);
        Object o = enhancer.create();
        return o;

    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib 动态代理事务开始");
        Object invoke = methodProxy.invoke(object, objects);
        System.out.println("Cglib 动态代理事务结束");
        return invoke;
    }
}

package com.evan.springboot.designStudy.proxyDemo;

import java.lang.reflect.Proxy;

/**
 * @author evanYang
 * @version 1.0
 * @date 2020/4/29 上午 11:06
 */
public class Client {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        UserJDkProxy userJDkProxy = new UserJDkProxy(userService);
        UserService o = (UserService) Proxy.newProxyInstance(userJDkProxy.getClass().getClassLoader(), userService.getClass().getInterfaces(), userJDkProxy);
        o.save();

        UserCglibProxy userCglibProxy = new UserCglibProxy();
        UserService instance = (UserService) userCglibProxy.getInstance(userService);
        instance.save();
    }
}

CGlib动态代理和JDK动态代理的区别

java动态代理是利用反射机制生成一个实现代理接口的匿名内部类
cglib是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理

Spring中
1,如果目标对象实现了接口,默认情况下回采用JDK的动态代理实现AOP
2,如果目标对象实现了接口,可以强制使用CGlib实现AOP
3,如果目标没有实现接口,必须采用Cglib库,spring会自动在jdk动态代理和cglib之间转换

JDK动态代理只能对实现了接口的类型生成代理,而不能针对类
Cglib是针对类实现代理,主要是对指定类生成一个子类,覆盖其中方法。
因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。


转载:https://blog.csdn.net/weixin_30409927/article/details/105838384
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场