Java的三种代理模式

 

  代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

Java的三种代理模式:静态代理,JDK动态代理,CGLIB动态代理

接口IUserDao,接口实现类UserDao。

public interface IUserDao {
    public void save();
}
public class UserDao implements IUserDao {
    @Override
    public void save() {
        System.out.println("数据保存操作");
    }
}

 

1.静态代理

静态代理在使用时,需要定义接口或者父类,目标对象与代理对象一起实现相同的接口或者是继承相同的父类。

缺点:

因为代理对象与目标对象需要实现相同的接口,使得每个目标对象,都有一个代理类,从而产生非常多的代理类。

 

public class UserDaoProxy implements IUserDao {
    //接收保存目标对象
    private IUserDao target;

    public UserDaoProxy(IUserDao target) {
        this.target = target;
    }

    @Override
    public void save() {

        System.out.println("开启事务...");
        //执行目标对象的方法(接口回调)
        target.save();
        System.out.println("提交事务...");

    }
}

public class TestProxy {

   /**
     * 静态代理测试
     */
    @Test
    public void testStaticProxy() {
        IUserDao target = new UserDao();
        UserDaoProxy userDaoProxy = new UserDaoProxy(target);
        System.out.println("静态代理userDaoProxy的class:" + userDaoProxy.getClass());
        userDaoProxy.save();
    }
}

 

2.JDK动态代理

动态代理也称为JDK代理,接口代理。动态代理借助于JDK的API实现,

Proxy类:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
  • ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
  • Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型
  • InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入

特点:

1.代理对象不需要实现接口,但是目标对象要实现接口,否则不能使用JDK动态代理;

2.代理对象是动态生成的,通过JDK的API,动态地在内存中创建代理对象。

第一种,不实现接口InvocationHandler。

首先,定义Proxy工厂类。

public class ProxyFactory {

    //维护一个目标对象
    private Object target;

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

    /**
     * 动态创建代理对象
     *
     * @return
     */
    public Object getProxyInstance() {
        // 指定目标对象使用的类加载器/目标对象的接口/事件处理器
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            /**
             *   该方法invoke被执行几次?------- 看代理对象调用方法几次
             *   代理对象调用接口相应方法 都是调用invoke
             * @param proxy 代理对象
             * @param method 目标方法的字节码对象
             * @param args 调用目标方法时的参数
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("开启事务...");
                //运用反射执行目标对象方法
                Object returnValue = method.invoke(target, args);
                System.out.println("提交事务...");
                return returnValue;
            }
        });
    }

}

然后,使用工厂类 


public class TestProxy {

  
    /**
     * JDK动态代理测试
     */
    @Test
    public void testDynamicProxy() {
        IUserDao target = new UserDao();
        // 第一种方式,ProxyFactory中的InvocationHandler是匿名类
        System.out.println("target对象class:" + target.getClass());
        ProxyFactory proxyFactory = new ProxyFactory(target);
        System.out.println("jdk动态代理proxyFactory的class" + proxyFactory.getProxyInstance().getClass().getName());

      
    }
」

第二种方式:实现接口InvocationHandler。

首先,实现InvocationHandler接口。

public class UserDaoInvocationHandler implements InvocationHandler {

    /**
     * 被代理的对象
     */
    private Object target;

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

    /**
     * 处理动态代理类上的所有方法调用
     * 本调用处理器根据这三个参数 进行预处理或分派到委托类实例上「反射」执行
     *
     * @param proxy  代理类
     * @param method 被调用的方法对象
     * @param args   方法入参
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开启事务...");
        Object returnValue = method.invoke(target, args);
        System.out.println("提交事务...");

        return returnValue;
    }
}

然后,使用Proxy.newProxyInstance(classLoader, interfaces, invocationHandler)

public class TestProxy {

    /**
     * JDK动态代理测试
     */
    @Test
    public void testDynamicProxy() {
        IUserDao target = new UserDao();

        // 第二种方式,实现InvocationHandler接口
        InvocationHandler invocationHandler = new UserDaoInvocationHandler(target);
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class[] interfaces = target.getClass().getInterfaces();
        IUserDao userDao2 = (IUserDao) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        System.out.println("jdk动态代理对象userDao2的class:" + userDao2.getClass().getName());
        userDao2.save();

    }
}

3.Cglib代理

Cglib代理,也称为子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。

特点:

1.代理对象和目标对象都不需要实现接口;

2.以目标对象子类的方式实现代理。

public class CglibProxyFactory {

    //目标对象
    private Object target;

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

    /**
     * 为目标对象创建一个代理对象
     *
     * @return 子类对象
     */
    public Object getProxyInstance() {
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(new MethodInterceptor() {
            /**
             *
             * @param object cglib生成的代理对象
             * @param method 目标对象方法(被拦截的方法)
             * @param objects 方法参数(被拦截方法的参数)
             * @param methodProxy 代理方法
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("开启事务...");
                Object returnValue = methodProxy.invoke(target, objects);
                System.out.println("提交事务...");
                return returnValue;
            }
        });

        //4.创建target类的子类(也是代理对象)
        return en.create();
    }


}
public class TestProxy {

    /**
     * CgLib动态代理测试
     */
    @Test
    public void testCglibProxy() {
        UserDao target = new UserDao();
        System.out.println("target对象class:" + target.getClass());
        IUserDao proxy1 = (IUserDao) new CglibProxyFactory(target).getProxyInstance();
        // 代理对象信息
        System.out.println("cglib动态代理对象proxy1的class:" + proxy1.getClass().getName());
        proxy1.save();

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值