关于代理的那些事

本文详细介绍了代理模式的概念及其在Java中的应用,包括静态代理、JDK动态代理和CGLIB动态代理三种实现方式,并通过示例代码展示了每种代理的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

静态代理

什么是代理,意思就是你不用去做,别人替你去做。比如说赚钱方面,我就是我老婆的Proxy,带小孩方面,我老婆是我的Proxy.

  • 员工的接口,包括有一个工作的方法
package staticproxy;

/**
 * @author by benny on 2016/1/2.
 * @version 1.0
 * @description
 */
public class EmployeeProxy implements Employee {

    private Employee employee;

    public EmployeeProxy() {
        this.employee = new EmployeeImpl();
    }

    @Override
    public void work(String name) {
        //方法之前
        before();
        employee.work(name);
        //方法之后
        after();
    }

    public void before(){
        System.out.println("准备上班");
    }

    public void after(){
        System.out.println("准备下班");
    }


}
  • 增加一个雇员的代理类,这样就不用写死在work方法里面了。
package staticproxy;

/**
 * @author by benny on 2016/1/2.
 * @version 1.0
 * @description
 */
public class EmployeeProxy {

    private Employee employee;

    public EmployeeProxy() {
        this.employee = new EmployeeImpl();
    }

    public void work() {
        //方法之前
        before();
        employee.work("benny");
        //方法之后
        after();
    }

    public void before(){
        System.out.println("准备上班");
    }

    public void after(){
        System.out.println("准备下班");
    }
}
  • 测试类
package staticproxy;

/**
 * @author by benny on 2016/1/2.
 * @version 1.0
 * @description 测试雇员的静态代理类
 */
public class EmployeeProxyTest {

    public static void main(String[] args) {
        Employee proxy = new EmployeeProxy();
        proxy.work("benny");
    }
}
  • 打印测试结果
    准备上班
    benny正在工作中!
    准备下班

动态代理

  • JDK动态代理

如果像上面那样每个类增加方法之类的都要写一个代理类的话,那么将会导出都是***Proxy类了,所以将这些Proxy重构为“动态代理”。


  • 写一个动态代理类
package jdkproxy;

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

/**
 * @author by benny on 2016/1/2.
 * @version 1.0
 * @description
 */
public class DynamicProxy implements InvocationHandler {

    private Object obj;

    //通过构造器将obj注入
    public DynamicProxy(Object obj){
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        before();
        //此处需要主次传入的参数 一个是我们注入进来的对象
        Object target = method.invoke(obj, args);
        after();
        return target;
    }

    public void before() {
        System.out.println("准备上班");
    }

    public void after() {
        System.out.println("准备下班");
    }


    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }
}
  • 测试类
package jdkproxy;

import java.lang.reflect.Proxy;

/**
 * @author by benny on 2016/1/2.
 * @version 1.0
 * @description
 */
public class DynamicProxyTest {

    public static void main(String[] args){
        //实例化雇员
        Employee employee = new EmployeeImpl();

        DynamicProxy proxy = new DynamicProxy(employee);
        //此处指定是哪一个接口,这样才能知道调用那个接口里的方法
        Employee employeeProxy = (Employee) Proxy.newProxyInstance(
                employee.getClass().getClassLoader(),
                employee.getClass().getInterfaces(),
                proxy);
        employeeProxy.work("benny");
    }
}

其实动态代理就是帮我们自动生成Xxx代理类的法宝。
需要注意,Proxy.newProxyInstance 方法的参数
Proxy.newProxyInstance(Xxx.getClass().getClassLoader(), Xxx.getClass().getInterfaces(), this);
this 一定是实现了InvocationHandler接口才能有this
从这个方法里就可以看出,要动态代理的类必须要实现接口才可以使JDK动态代理。

  • 参数1:ClassLoader
  • 参数2:该实现类的所有接口
  • 参数3:动态代理对象

调用完了还要强制转换一下。


  • DynamicProxy重构
package jdkproxy;

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

/**
 * @author by benny on 2016/1/2.
 * @version 1.0
 * @description
 */
public class DynamicProxy implements InvocationHandler {

    private Object obj;

    //通过构造器将obj注入
    public DynamicProxy(Object obj){
        this.obj = obj;
    }
-------------------/*增加此方法*/---------------------------

    //提取获得动态代理的方法
    public <T> T getDynamicProxy(){
        return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
    }

-------------------/*增加此方法*/---------------------------

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        before();
        Object target = method.invoke(obj, args);
        after();
        return target;
    }

    public void before() {
        System.out.println("准备上班");
    }

    public void after() {
        System.out.println("准备下班");
    }


    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }
}
  • 测试类
package jdkproxy;

/**
 * @author by benny on 2016/1/2.
 * @version 1.0
 * @description
 */
public class DynamicProxyTest {

    public static void main(String[] args){

        DynamicProxy dynamicProxy = new DynamicProxy(new Employee());

        Employee employeeProxy = dynamicProxy.getDynamicProxy();

        employeeProxy.work("benny");
    }
}

  • CGLIB动态代理

用了DynamicProxy,还是蛮好的,好的地方是,接口变了,这个动态代理类不用变。静态代理就不一样了,接口变了实现类还要变,代理类也要变,JDK动态代理类也不是万能的,比如说代理一个没有任何接口的类,它就无用武之地了。

  • 第一步:实现MethodInterceptor接口。
  • 第二步:重写intercept方法。Object o = methodProxy.invokeSuper( (被代理的对象)object , args ) ;
  • 第三步:获得代理类 getProxy(Class clazz)
    return Enhancer.create( clazz , this ) ;

  • 动态代理类
package cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author by benny on 2016/1/3.
 * @version 1.0
 * @description
 */
public class CGLibProxy implements MethodInterceptor {


    private static CGLibProxy instance = new CGLibProxy();

    private CGLibProxy() {
    }

    public CGLibProxy getCGLibProxy() {
        return instance;
    }

    public <T> T getProxy(Class<T> clazz) {
        return (T) Enhancer.create(clazz, this);
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object o1 = methodProxy.invokeSuper(o, objects);
        after();
        return o1;
    }

    public void before() {
        System.out.println("准备上班");
    }

    public void after() {
        System.out.println("准备下班");
    }
}
  • 测试类
package cglib;

/**
 * @author by benny on 2016/1/3.
 * @version 1.0
 * @description
 */
public class CGLibProxytest {

    public static void main(String[] args) {
        EmployeeImpl proxy = CGLibProxy.getCGLibProxy().getProxy(EmployeeImpl.class);
        proxy.work("benny");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值