Spring与代理模式

Spring与代理模式

  • 为了阐述清楚spring中的一个非常重要的模块AOP,必须要了解代理模式
  • 代理模式就是为其他对象提供一种代理以控制对这个对象的访问
  • 白话解释为:
    • 比如A对象要做一件事,在没有代理之前,需要自己亲自动手
    • 在对A代理后,这件事就由A的代理来做
  • 代理其实是在原始的实例前后增加了一层处理,这也就是AOP概念的初级轮廓

1.静态代理

  • 在程序的运行前就已经存在代理类的字节码文件,代理类和原始类的关系在运行前就已经确定!

代码:

UserDao.java

public interface UserDao {
    void add();
}

UserDaoImpl.java

public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("模拟,添加用户!");
    }
}

UserDaoProxy.java

public class UserDaoProxy implements UserDao {
    // 授权
    private UserDao ud = new UserDaoImpl();
    @Override
    public void add() {
        System.out.println("代理操作:开启事务,为你遮风挡雨");
        ud.add();
        System.out.println("代理操作:提交事务,为你保驾护航");
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        UserDao ud = new UserDaoProxy();
        ud.add();
    }
}

总结:如果增加一个方法,除了实现类需要实现这个方法外,所有的代理类也要实现这个方法。增加了代码的维护成本。

静态代理就是有这样的问题,想解决这个问题,使用“动态代理”

2.动态代理-JDK

  • 动态代理类的源码是在程序运行期间,通过JVM反射等机制动态生成,代理类和委托类的关系是运行时才确定的

UserDao.java

public interface UserDao {
    void add();

    void findAll();
}

UserDaoImpl.java

public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("模拟,保存用户!");
    }

    @Override
    public void findAll() {
        System.out.println("查询所有用户");
    }
}

UserDaoProxy.java

public class UserDaoProxy implements InvocationHandler {

    /// 目标,委托类
    private Object target;

    // 授权
    public Object getProxyInstance(Object object) {
        this.target = object;
        /*
        newProxyInstance(1,2,3);
        1:目标对象使用的类加载器
        2:目标对象实现的所有接口
        3:代理对象
         */
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        Object result = null;
        //查询方法不需要加事务,其他的增删改都需要事务管理
        // findAll,findOneById
        if (methodName.indexOf("find") >= 0) {  // 匹配查询方法
            result = method.invoke(target, args); //执行目标方法
        } else {  //增删改
            System.out.println("开始事务");
            result = method.invoke(target, args);//执行目标方法
            System.out.println("结束事务");
        }
        return result;
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        // 目标对象
        UserDao ud = new UserDaoImpl();
        // 代理对象
        UserDaoProxy proxy = new UserDaoProxy();
        // 代理实例
        UserDao proxyInstance = (UserDao) proxy.getProxyInstance(ud);

        proxyInstance.add();
        System.out.println("----------------------------");
        proxyInstance.findAll();
    }
}

总结:使用JDK生成的动态代理的前提是目标对象必须有实现的接口,这里又引入一个新的问题,如果某个类没有实现接口,就不能用这种代理方式。Cglib代理就是解决这个问题的。

3.动态代理-Cglib

  • 如果是普通的项目,需要引入cglib-xxx.jar和ams-xx.jar两个文件
  • 如果是spring项目,spring对cglib是支持的。
  • 此代理方式的原理:拦截器(80%和过滤器概念一样)

UserDao.java

public class UserDao {
    public void add(){
        System.out.println("模拟,保存用户!");
    }
}

UserDaoProxy.java

package proxy3;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @BelongsProject: spring2
 * @Author: GuoAn.Sun
 * @CreateTime: 2020-06-29 12:12
 * @Description: ${Description}
 */
public class UserDaoProxy implements MethodInterceptor {
    //目标对象
    private Object target;

    //获得代理对象
    public Object getInstance( Object target){
        this.target = target;
        //创建增强对象
        Enhancer enhancer = new Enhancer();
        //设置增强的父类
        enhancer.setSuperclass(this.target.getClass());
        //设置回调方法
        enhancer.setCallback(this);
        //返回代理对象
        return enhancer.create();
    }

    // 回调方法
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("事务开始");
        Object result = methodProxy.invoke(target, objects);
        System.out.println("事务结束");
        return result;
    }

}

Test.java

public class Test {
    public static void main(String[] args) {
        //目标
        UserDao ud = new UserDao();
        //代理
        UserDaoProxy proxy = new UserDaoProxy();

        UserDao dao = (UserDao) proxy.getInstance(ud);

        dao.add();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值