设计模式之-代理模式

本文深入探讨了Java中的三种动态代理实现方式:静态代理、JDK动态代理和CGLib动态代理。通过示例代码详细解释了每种代理模式的工作原理,展示了如何在方法调用前后添加额外的操作,如事务管理。同时指出JDK动态代理要求被代理类实现接口,而CGLib则通过字节码技术实现无接口代理。

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

一:静态代理

首先要定义一个公共的接口,供代理类和被代理类实现,供代理类有增强点

package cn.com.staticProxy;
/**
 * * 
*<p>Title: IUserDao</p>
* <p>Description:公共的接口</p>
* <p>Company: </p>
* @author Administrator
* @date 2019年4月24日 下午4:15:12
 */
public interface IUserDao {

    void save();
    void find();
}

被代理类:

package cn.com.staticProxy;

public class UserDao implements IUserDao{
/**
 * 被代理类或者叫代理目标类
 */
    @Override
    public void save() {
        // TODO Auto-generated method stub
        
        System.out.println("模拟保存用户");
        
    }

    @Override
    public void find() {
        // TODO Auto-generated method stub
        System.out.println("模拟查找用户");
        
    }

}

对比一下直接调用:

package cn.com.staticProxy;
/**
 * * 
*<p>Title: Test2</p>
* <p>Description:直接使用被代理类 </p>
* <p>Company: </p>
* @author Administrator
* @date 2019年4月24日 下午4:18:39
 */
public class Test2 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        IUserDao udp=new UserDao();
        udp.save();
        System.out.println("-------------------");
        udp.find();
    }

}

结果:

模拟保存用户
-------------------
模拟查找用户

代理类:

package cn.com.staticProxy;

public class UserDaoProxy implements IUserDao {

    private UserDao ud = new UserDao();

    @Override
    public void save() {
        // TODO Auto-generated method stub

        System.out.println("代理操作,开启事务");
        ud.save();
        System.out.println("代理操作,关闭事务");
    }

    @Override
    public void find() {
        // TODO Auto-generated method stub
        System.out.println("代理操作,开启事务");
        ud.find();
        System.out.println("代理操作,关闭事务");
    }

}

代理类调用:

package cn.com.staticProxy;

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        IUserDao udp=new UserDaoProxy();//不是直接new UserDao对象,而是通过代理类创建对象。因为都实现了IUserDao接口
        udp.save();
        System.out.println("-------------------");
        udp.find();
    }

}

结果:

代理操作,开启事务
模拟保存用户
代理操作,关闭事务
-------------------
代理操作,开启事务
模拟查找用户
代理操作,关闭事务

二、JDK动态代理

沿用上面的例子
JDK的动态代理存在不足,即被代理类必须要有实现的接口,如没有接口则无法使用JDK动态代理

package cn.com.dynamicProxy;

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

import cn.com.staticProxy.IUserDao;
import cn.com.staticProxy.UserDao;

public class DynamicProxy implements InvocationHandler{
    //被代理类的实例
    private IUserDao iud=null;//接口不能实例化,但可以进行申明

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        Object result=null;
        System.out.println("开始JDK动态代理");
        method.invoke(iud, args);
        System.out.println("结束JDK动态代理");
        return result;
    }
    //构造方法
    public DynamicProxy(IUserDao iud){
        this.iud=iud;
    }
    
}

需要实现JDK中的InvocationHandler接口,实现其中的invoke方法,在此方法中通过反射的方式调用被代理类的方法,可以在方法执行前或后进行别的处理,下面看测试代码:

package cn.com.dynamicProxy;

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

import cn.com.staticProxy.IUserDao;
import cn.com.staticProxy.UserDao;

public class Test2 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        UserDao ud=new UserDao();
        
        DynamicProxy dp=new DynamicProxy(ud);
        
        //动态生成代理对象,不像静态代理需要提前代理,而是在需要是调用Proxy.newProxyInstance生成代理对象
        //ud.getClass().getClassLoader()是通过反射获取ud的构造器,(用哪个类加载器去加载代理对象)
        //ud.getClass().getInterfaces()获得ud的所有接口,也就获得了需要被代理的方法,因为实体类要实现这些方法(动态代理类需要实现的接口)
        //dp(动态代理方法在执行时,会调用dp里面的invoke方法去执行),这个类必须是实现了InvocationHandler接口的
        IUserDao iud=(IUserDao)Proxy.newProxyInstance(ud.getClass().getClassLoader(), ud.getClass().getInterfaces(), dp);
        iud.save();
        System.out.println("--------------");
        iud.find();
        
    }

    
}

三、cglib动态代理

需要引入CGLib的jar包
在这里插入图片描述
要使用CGLib代理需要实现其MethodInterceptor接口:


package cn.com.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class MyMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // TODO Auto-generated method stub
        
        System.out.println("开始CGLib动态代理");
        Object object=proxy.invokeSuper(obj, args);
        System.out.println("结束CGLib动态代理");
        return object;
    }

}

测试代码:

package cn.com.cglib;

import cn.com.staticProxy.UserDao;
import net.sf.cglib.proxy.Enhancer;

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(UserDao.class);
        enhancer.setCallback(new MyMethodInterceptor());
        //生成代理类
        UserDao ud=(UserDao) enhancer.create();
        ud.save();        System.out.println("----------------");
        ud.find();
        
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值