谈谈Java中的代理

作者: Joepis | 来源:发表于2017-02-19 19:23 被阅读126次

摘要: 原创出处 http://peijie2016.gitee.io 欢迎转载,保留摘要,谢谢!

代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,实现对相关方法增强。比如加入事务、日志、报警发邮件等操作。

java.png

静态代理

静态代理,就是由程序员手动编写代理类或者用工具生成代理类的代码,再进行编译生成class文件,实现代理。比如简单工厂模式。

用法:

  • 代理类和目标类都实现相同接口。
  • 代理类持有目标类的引用。

缺点:
静态代理要为每个目标类创建一个代理类,当需要代理的对象太多,那么代理类也变得很多。代理类违背了可重复代理只写一次的原则。

动态代理

为了解决静态代理的缺点,于是引入了动态代理。
它有一个好处,那就是不用写很多代理类,生成的代理类数量是固定的。
一般动态代理分为2种:

JDK动态代理

JDK动态代理是JDK自带的,不依赖第三方框架。
它的实现原理,就是利用Java的反射机制,创建一个实现接口的代理类。

用法:

  • 被代理对象必须实现接口。
  • 代理对象由代理工厂自动生成。

下面贴个例子

接口类:

public interface Subject {   
  public void doSomething();   
}

实现类:

public class RealSubject implements Subject {   
  public void doSomething() {   
    System.out.println("do 了 some thing ...");   
  }   
} 

代理工厂:

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

public class ProxyHandler implements InvocationHandler {
    private Object target;

    //绑定委托对象,并返回代理类
    public Object bind(Object target) {
        this.target = target;
        //绑定该类实现的所有接口,取得代理类 
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }
    
    @Override
    public Object invoke(Object proxy , Method method , Object[] args)throws Throwable {
        Object result = null;
        //这里就可以进行所谓的AOP编程了
        //在调用具体函数方法前,执行功能处理
        result = method.invoke(target, args);
        //在调用具体函数方法后,执行功能处理
        return result;
    }
}

测试类:

public class TestProxy {
    public static void main(String args[]) {
           ProxyHandler proxy = new ProxyHandler();
           //绑定该类实现的所有接口
           Subject sub = (Subject) proxy.bind(new RealSubject());
           sub.doSomething();
    }
}

CGLIB代理

使用CGLIB代理需要引入CGLIB库,它使用字节码技术实现代理。

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
      
public class CGLibProxy implements MethodInterceptor {    
    
    private Object targetObject;// CGLib需要代理的目标对象    
    
    public Object createProxyObject(Object obj) {    
        this.targetObject = obj;    
        Enhancer enhancer = new Enhancer();    
        enhancer.setSuperclass(obj.getClass());    
        enhancer.setCallback(this);    
        Object proxyObj = enhancer.create();    
        return proxyObj;// 返回代理对象    
    }    
    
    public Object intercept(Object proxy, Method method, Object[] args,    
            MethodProxy methodProxy) throws Throwable {    
        Object obj = null;    
        if ("addUser".equals(method.getName())) {// 过滤方法    
            checkPopedom();// 检查权限    
        }    
        obj = method.invoke(targetObject, args);    
        return obj;    
    }    
    
    private void checkPopedom() {    
        System.out.println("检查权限  checkPopedom()!");    
    }    
}
public class Test {
    
    public static void main(String[] args) {
    
        Subject sub = (Subject) new CGLibProxy().createProxyObject(new RealSubject());
        sub.doSomething();
}

2种动态代理的区别

JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而CGLIB动态代理是利用asm开源包,加载代理对象类的class文件,修改其字节码生成子类来处理。

在 Spring 中,

  • 如果目标对象实现了接口,默认情况下会采用JDK动态代理实现AOP
  • 如果目标对象实现了接口,可以强制使用CGLIB实现AOP
  • 如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换

如何强制使用CGLIB实现AOP?

  • 添加CGLIB依赖
  • 在Spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
  • 如果是SpringBoot,在配置文件设置spring.aop.proxy-target-class=true

JDK动态代理和CGLIB字节码生成的区别?

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

相关文章

  • 谈谈Java中的代理!

    静态代理 静态代理,就是由程序员手动编写代理类或者用工具生成代理类的代码,再进行编译生成class文件,实现代理。...

  • 谈谈Java中的代理

    摘要: 原创出处 http://peijie2016.gitee.io 欢迎转载,保留摘要,谢谢! 代理是Java...

  • 谈谈Java的动态代理

    动态代理机制的设计的目的是解耦,在很多类中,一个函数需要重复写,如果每个类中都有该函数,造成代码的耦合,单独提出来...

  • 安卓反射和动态代理的应用

    提纲 java反射基础 反射在Android中的应用 Java动态代理 动态代理在Android的应用 java反...

  • 第6讲 | 动态代理是基于什么原理?

    谈谈 Java 反射机制,动态代理是基于什么原理? 典型回答 反射机制是 Java 语言提供的一种基础功能,赋予程...

  • 保存java 动态代理生成的字节码文件

    保存java 动态代理生成的字节码文件 在Java中,常用的动态代理技术有JDK的动态代理和cglib动态代理,不...

  • 【啃啊啃 Spring5 源码】细碎三:AOP两种动态代理的区别

    spring 中 AOP是基于 “动态代理” 实现,其采用了两种方式: java代理:采用java内置的代理API...

  • 浅谈JAVA代理

    前言 什么是java代理,为什么要学习java代理。在很多框架中都会用到,如Spring中的AOP、Hadoop中...

  • Java动态代理

    Java中的动态代理 一、使用 简介 在Java中要创建一个动态代理对象,需要使用 Proxy.newProxyI...

  • Java中的代理

    今天看Java核心卷时,看到代理这一部分很晕,虽然之前对代理有一些基本了解,但并没有深入了解,而且代理的内容也是我...

网友评论

    本文标题:谈谈Java中的代理

    本文链接:https://www.haomeiwen.com/subject/pebjwttx.html