Spring,AOP,JDK动态代理、CGLIB代理

关于AOP的基本介绍,参考:Spring深入浅出(十二),AOP,AspectJ,基于XML开发

AOP的代理就是由AOP框架动态生成的一个对象,该对象可以作为目标对象使用。Spring中的AOP代理,可以是JDK动态代理,也可以是CGLIB代理(Code Generation Library)。

一、JDK动态代理

1. 创建接口

package com.itheima.jdk;

public interface UserDao {
    public void addUser();

    public void deleteUser();
}

2. 创建实现类

package com.itheima.jdk;

import org.springframework.stereotype.Repository;

// 目标类
@Repository("userDao")
public class UserDaoImpl implements UserDao {
    public void addUser() {
        System.out.println("添加用户");
    }

    public void deleteUser() {
        System.out.println("删除用户");
    }
}

3. 创建切面类

该类实现InvocationHandler接口,并实现接口中invoke()方法,所有动态代理类所调用的方法都会交由该方法处理。

package com.itheima.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.itheima.aspect.MyAspect;

/**
 * JDK代理类
 */
public class JdkProxy implements InvocationHandler {
    // 声明目标类接口
    private UserDao userDao;

    // 创建代理方法
    public Object createProxy(UserDao userDao) {
        this.userDao = userDao;
        // 1.类加载器
        ClassLoader classLoader = JdkProxy.class.getClassLoader();
        // 2.被代理对象实现的所有接口
        Class[] clazz = userDao.getClass().getInterfaces();
        // 3.使用代理类,进行增强,返回的是代理后的对象
        return Proxy.newProxyInstance(classLoader, clazz, this);
    }

    /*
     * 所有动态代理类的方法调用,都会交由invoke()方法去处理 proxy 被代理后的对象 method 将要被执行的方法信息(反射) args
     * 执行方法时需要的参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 声明切面
        MyAspect myAspect = new MyAspect();
        // 前增强
        myAspect.check_Permissions();
        // 在目标类上调用方法,并传入参数
        Object obj = method.invoke(userDao, args);
        // 后增强
        myAspect.log();
        return obj;
    }
}

4. 创建主程序

package com.itheima.jdk;

public class JdkTest {
    public static void main(String[] args) {
        // 创建代理对象
        JdkProxy jdkProxy = new JdkProxy();
        // 创建目标对象
        UserDao userDao = new UserDaoImpl();
        // 从代理对象中获取增强后的目标对象
        UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao);
        // 执行方法
        userDao1.addUser();
        userDao1.deleteUser();
    }
}

5. 运行结果

模拟检查权限...
添加用户
模拟记录日志...
模拟检查权限...
删除用户
模拟记录日志...

二、CGLIB代理

使用JDK动态代理的对象必须实现一个或多个接口。如果要对没有实现接口的类进行代理,那么可以使用CGLIB代理。

1. 创建实现类

package com.itheima.cglib;
//目标类
public class UserDao {
    public void addUser() {
        System.out.println("添加用户");
    }
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

2. 创建切面类

该代理类需要实现MethodInterceptor接口,并实现接口中的intercept方法。

package com.itheima.cglib;

import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import com.itheima.aspect.MyAspect;

// 代理类
public class CglibProxy implements MethodInterceptor {
    // 代理方法
    public Object createProxy(Object target) {
        // 创建一个动态类对象
        Enhancer enhancer = new Enhancer();
        // 确定需要增强的类,设置其父类
        enhancer.setSuperclass(target.getClass());
        // 添加回调函数
        enhancer.setCallback(this);
        // 返回创建的代理类
        return enhancer.create();
    }

    /**
     * proxy CGlib根据指定父类生成的代理对象 method 拦截的方法 args 拦截方法的参数数组 methodProxy
     * 方法的代理对象,用于执行父类的方法
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 创建切面类对象
        MyAspect myAspect = new MyAspect();
        // 前增强
        myAspect.check_Permissions();
        // 目标方法执行
        Object obj = methodProxy.invokeSuper(proxy, args);
        // 后增强
        myAspect.log();
        return obj;
    }
}

3.创建主程序

package com.itheima.cglib;
// 测试类
public class CglibTest {
    public static void main(String[] args) {
        // 创建代理对象
        CglibProxy cglibProxy = new CglibProxy();
             // 创建目标对象
        UserDao userDao = new UserDao();
         // 获取增强后的目标对象
        UserDao userDao1 = (UserDao)cglibProxy.createProxy(userDao);
        // 执行方法
        userDao1.addUser();
        userDao1.deleteUser();
    }
}

4.  输出结果

模拟检查权限...
添加用户
模拟记录日志...
模拟检查权限...
删除用户
模拟记录日志...

本文参考:《Java EE企业级应用开发教程》

posted @ 2021-07-23 14:37  那些年的事儿  阅读(184)  评论(0编辑  收藏  举报