Java静态代理和动态代理

前言

  • 动态代理在Java中有着广泛的应用,比如Spring AOP、Mybatis、RPC远程调用、Java注解对象获取、日志、用户鉴权、全局性异常处理、性能监控,甚至事务处理等。

代理模式

  • 代理模式是给某一个对象提供一个代理,并由代理对象来控制对真实对象的访问
  • 代理模式根据Java字节码创建的时机划分为静态代理和动态代理

静态代理

  • 静态代理也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了
  • 代理类
public class StaticProxy {

    private  UserMapper target;

    public StaticProxy(UserMapper mapper)
    {
        this.target =mapper;
    }

    public List<Pojo> select()
    {
        before();
        List<Pojo> res= target.select();
        after();
        return  res;
    }

    public void before(){
        System.out.print(String.format("Load start:[%s]\r\n", new Date().toString()));
    }

    public void after() {
        System.out.print(String.format("Load end:[%s]\r\n", new Date().toString()));
    }
}
  • 测试类
@Service
@Transactional
@Component
public class TestFunc {

    @Autowired
    private UserMapper oMapper;

    @PostConstruct
    private  void test()
    {
        System.out.print("Load data from db start \r\n");

        StaticProxy proxy = new StaticProxy(oMapper);

        List<Pojo> results = proxy.select();
        //List<Pojo> results = oMapper.select();
    }
  • 代理类实际上是目标对象的增强类

静态代理的缺点

  • 虽然没有入侵实体类,但是实现目标类的多个接口,导致代理类过大
  • 目标类的修改都要同步修改代理类,耦合严重

动态代理

  • 动态代理的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代理类的字节码文件
  • 代理类
public class MapperProxy implements InvocationHandler {

    private  Object target;

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

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object obj = method.invoke(target, args);
        after();
        return obj;
    }

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

    private void before(){
        System.out.print(String.format("Load start:[%s]\r\n", new Date().toString()));
    }

    private void after() {
        System.out.print(String.format("Load end:[%s]\r\n", new Date().toString()));
    }
}
  • 测试类
    @Autowired
    private UserMapper oMapper;

    @PostConstruct
    private  void test()
    {
        System.out.print("Load data from db start \r\n");

        MapperProxy proxy = new MapperProxy(oMapper);
        UserMapper mapper = proxy.getProxy();
        mapper.select();

        //List<Pojo> results = oMapper.select();
    }

动态代理的划分

  • 接口级别代理:JDK动态代理,动态代理类实现InvocationHandler接口
  • 方法级别代理:Cglib代理,在内存中构建一个子类对象从而实现对目标对象功能的扩展
  • 如果是一个对象的 一个或多个接口,可以使用JDK动态代理;如果目标类没有接口,可以使用Cglib代理实现

动态代理的优点

  1. 解决了静态代理中冗余的代理实现类问题。

  2. 系统扩展性和维护性增强。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章