Spring AOP-代理模式

Spring AOP代理模式

在OOP的对象中,做日志记录,权限校验等如果都让面向对象来做,会产生大量冗余代码。所以引入切面去织入相关逻辑。面向切面编程使用代理模式

一、代理模式

官方定义:为其他对象提供一种代理以控制对这个对象的访问。

代理类是在之前类的基础上做了一层封装。java中有静态代理、JDK动态代理、CGLib代理

静态代理指的是代理类是在编译期就存在的,动态代理指代理类在运行期动态生成

二、静态代理

程序在运行之前就已经知道代理类和被代理类的关系。

  1. 定义一个公共接口
  2. 定义被代理类
  3. 定义代理类

1.定义一个公共接口

public interface IUserDao {
    void save();
}

2.定义被代理类

public class UserDao implements IUserDao {
    @Override
    public void save() {
        System.out.println(" 保存用户 ");
    }
}

3.定义代理类

public class UserDaoProxy implements IUserDao{

    private UserDao userDao = new UserDao();

    @Override
    public void save() {
        System.out.println("代理操作,开启事务");
        userDao.save();
        System.out.println("代理操作,关闭事务");
    }


    public static void main(String[] args) {
        IUserDao userDao = new UserDaoProxy();
        userDao.save();
    }
}

在这里插入图片描述

三、JDK动态代理

改动静态代理代码使之成为JDK动态代理

  1. 实现InvocationHandler
  2. 重写invoke方法
  3. 建立代理对象和真是对象的代理关系调用Proxy.newProxyInstance()
/**
 * jdk动态代理
 */
public class DynamicProxy implements InvocationHandler {

    //被代理类实例
    private Object target = null;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始JDK动态代理");
        Object result = method.invoke(target, args);
        System.out.println("结束JDK动态代理");
        return result;
    }

    /**
     * 建立代理对象和真实对象的代理关系,并返回代理对象
     * @param target
     * @return
     */
    public Object bind(Object target){
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);

    }

    public static void main(String[] args) {
        DynamicProxy dynamicProxy = new DynamicProxy();
        IUserDao iUserDao = (IUserDao) dynamicProxy.bind(new UserDao());
        iUserDao.save();
    }
}

在这里插入图片描述

从上面代码看出:代理类是由Proxy.newProxyInstance方法动态生成的,生成对象后使用“iUserDao.save()”的方式进行方法调用,代理类的被代理类的关系只有在执行这行代码的时候才会生成,因此成为动态代理。

但是必须要使UserDao实现IUserDao才能使用JDK动态代理(从newProxyInstance方法的第二个参数可得知,必须传入被代理类的实现接口),如果没有实现需要CGLib动态代理。

四、CGLib动态代理

CGLib动态代理使用继承被代理类,使用其子类的方式弥补了代理类没有接口的不足。

使用CGLib需要引入第三方类库:

在这里插入图片描述

  1. 导入cglib和asm jar包
  2. 实现MethodInterceptor的intercept方法实现代理逻辑
  3. 使用Enhancer创建出代理类
public class MyMethodIntercaptor implements MethodInterceptor {

    /**
     * 代理逻辑方法
     * @param o             代理对象
     * @param method        方法
     * @param objects       方法参数
     * @param methodProxy   方法代理
     * @return              代理逻辑返回
     * @throws Throwable    异常
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("开始CGLib动态代理");
        Object object = methodProxy.invokeSuper(o,objects);
        System.out.println("结束CGLib动态代理");
        return object;
    }

    /**
     * 生成CGLib代理对象
     * @param cls   被代理类
     * @return
     */
    public Object getProxy(Class cls){
        //CGLib enhancer增强类对象
        Enhancer enhancer = new Enhancer();
        //设置增强类型
        enhancer.setSuperclass(cls);
        //定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法
        enhancer.setCallback(this);
        //生成并返回代理对象
        return enhancer.create();
    }


    public static void main(String[] args) {
        MyMethodIntercaptor myMethodIntercaptor = new MyMethodIntercaptor();
        UserDao userDao = (UserDao) myMethodIntercaptor.getProxy(UserDao.class);
        userDao.save();
    }
}

在这里插入图片描述

从上面代码看出:使用Enhancer生成代理类,需要设置被代理类,也就是父类

五、总结

静态代理维护成本比较高,需要一个被代理类和代理类,而且需要实现相同接口。

JDK动态代理需要实现InvocationHandler.invoke()方法去创建代理逻辑。使用Proxy.newProxyInstance建立代理逻辑关系

CGLib动态代理需要引入包并实现MethodInterceptor.intercept()方法去创建代理逻辑。使用Enhancer去建立代理逻辑关系。

JDK动态代理和CGLib动态代理区别:

JDK需要被代理类实现接口。CGLib则是生成被代理类的子类,要求被代理类不能使用final,因为final不能被继承。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值