且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Spring代理模式

更新时间:2022-06-22 16:47:42

代理有静态代理、动态代理和cglib代理

静态代理:1.目标类必须实现一个接口,比如dao层的先写一个接口,再写一个接口的dao实现类,静态代理就是对这个实现类进行代理
                 2. 必须实现和目标对象(需要代理的类的对象)一样的接口,就是这个目标对象实现了什么接口,静态代理类就必须实现什么接口
弊端:如果目标类方法太多岂不是所有的方法都要写一下?太麻烦

静态代理
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("提交事务...");
    }
}


动态代理:1.和静态代理一样也是目标类必须实现接口
                  2.代理类不用必须实现和目标类一样的接口,是一个方法,给里面有三个参数,有一个参数是要指定目标类实现接口的类型,(注意指明的是实现接口的类型)

动态代理
public class ProxyFactory {

    // 维护一个目标对象
    private Object target;
    public ProxyFactory(Object target){
        this.target = target;
    }

    // 给目标对象,生成代理对象  
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(), 
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @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;
                    }
                });
    }
}


cglib代理:1.目标类没有实现的接口,是以子类的形式代理!
                   2.如果你又不想像静态代理那样实现相同的接口重写所有的方法,也不想像动态代理那种指明接口类型或者说目标对象根本没有实现接口
                   3.用cglib的方法可以实现,两个方法,看下面代码。
                    4.使用cglib代理的话是需要导包的,cglib.jar,但是spring-core.jar包中里面有引入这个cglib.jar的包,也就是导了spring的包就可以用了。
cglib代理
public class ProxyFactory implements MethodInterceptor{
    // 维护目标对象
    private Object target;
    public ProxyFactory(Object target){
        this.target = target;
    }

    // 给目标对象创建代理对象
    public Object getProxyInstance(){
        //1. 工具类
        Enhancer en = new Enhancer();
        //2. 设置父类
        en.setSuperclass(target.getClass());
        //3. 设置回调函数
        en.setCallback(this);
        //4. 创建子类(代理对象)
        return en.create();
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {

        System.out.println("开始事务.....");

        // 执行目标对象的方法
        Object returnValue = method.invoke(target, args);

        System.out.println("提交事务.....");

        return returnValue;
    }
}


spring中的代理模式:根据目标对象是否有实现接口动态的选择代理的模式。
                                    1.如果目标类有实现的接口就使用动态代理
                                    2.如果目标类没有实现的接口就使用cglib代理

 为什么上层向下层提供的是接口支持,而不是具体的实现类?

  这里面涉及到spring中的事务管理,是aop方式,aop又涉及到代理,代理分为三种,静态、动态、cglib代理。
  具体三种代理的区别和实现上面展示了
  这里值得一说的是如果你用动态代理需要告诉spring一个被代理类的父类对象,动态代理是以目标类子类的形式代理;
  如果使用cglib代理被代理类是要继承接口的。

  换个角度看,如果你的dao或者service层写了接口定义方法,实体类是实现这个接口,那么spring就给你采用cglib代理,
  如果你的dao或者service层是直接写实现类,那么spring就给你采用jdk动态代理
  所以写代码时要细心点,比如说如果你写具体实现类是实现接口,spring给你采用cglib代理,
  你糊涂的在下层调用和注入的时候是直接用实现类,
  那么是会报错的,因为你告诉spring用cglib代理,而你在下层用的时候用jdk动态代理,肯定冲突啊。