Spring学习——JDK动态代理和CGLIB动态代理

AOP面向切面 Java代理

通过spring进行配置
https://blog.csdn.net/wilbur_xieyj/article/details/88981453

静态代理

  1. 定义接口
package cn.edu.zucc.blog.dao;
/**
 * 定义一个用户接口
 * @author xyj
 */
public interface UserDao {
    public void addUser();
    public void removeUser();
}
  1. 实现接口
package cn.edu.zucc.blog.dao;

/**
 * userDao接口的实现类
 * @author xyj
 */
public class UserDaoImpl implements UserDao{
    @Override
    public void addUser() {
        System.out.println("this is addUser");
    }

    @Override
    public void removeUser() {
        System.out.println("this is removeUser");
    }
}
  1. 定义接口的代理类,在原方法调用之前和之后加入预处理与调用结束之后的操作
package cn.edu.zucc.blog.staticProxy;

import cn.edu.zucc.blog.dao.UserDao;
/**
 * 通过组合原有实现类的方式实现静态代理
 * @author xyj
 */
public class UserDaoProxy implements UserDao {

    private UserDao userDao;

    /**
     * 获取原本调用的实现类
     * @param userDao 原有实现类
     */
    public UserDaoProxy(UserDao userDao){
        this.userDao=userDao;
    }
    @Override
    public void addUser() {
        //前置操作
        System.out.println("before : addUser");
        //调用原有方法
        userDao.addUser();
        //后置操作
        System.out.println("after : addUser");
    }

    @Override
    public void removeUser() {
        //前置操作
        System.out.println("before : removeUser");
        //调用原有方法
        userDao.removeUser();
        //后置操作
        System.out.println("after : removeUser");
    }
}
  1. 测试Test
package cn.edu.zucc.blog.staticProxy;

import cn.edu.zucc.blog.dao.UserDao;
import cn.edu.zucc.blog.dao.UserDaoImpl;

public class Test {
    public static void main(String[] args) {
        //创建原有方法
        UserDao dao = new UserDaoImpl();
        //创建代理类
        UserDao userDao = new UserDaoProxy(dao);
        
        //通过代理类实现方法
        userDao.addUser();
        userDao.removeUser();
    }
}

静态代理太过麻烦了,而且只能对应代理一个接口。所以看看就行。

JDK动态代理

  1. 首先接口与实现类与之前一致不做更改
  2. 静态代理方法放弃,改用JDK代理,继承InvocationHandler 这里用的是JDK代理小心导错包
package cn.edu.zucc.blog.jdkProxy;

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

/**
 * JDK代理
 * 注:只能代理接口中定义的方法
 * @author xyj
 */
public class UserJDKProxy implements InvocationHandler {
    private Object target;
    /**
     * 获取原本调用的实现类
     * @param target 原有实现类
     */
    public UserJDKProxy(Object target){
        this.target=target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //前置操作
        System.out.println("before method : "+method.getName());
        //通过反射调用原本使用的方法
        Object result = method.invoke(target,args);
        //后置操作
        System.out.println("after method");
        return result;
    }
}
  1. 测试Test
package cn.edu.zucc.blog.jdkProxy;

import cn.edu.zucc.blog.UserDao;
import cn.edu.zucc.blog.UserDaoImpl;

import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        //动态代理
        UserDao userDao = (UserDao) Proxy.newProxyInstance(
                //指定当前目标对象使用的类加载器,获取加载器的方法是固定的
                UserDao.class.getClassLoader(),
                //指定目标对象实现的接口类型,使用泛型方式确认类型
                new Class[]{UserDao.class},
                //指定动态处理器,执行目标对象方法时会触发事件处理器的方法
                new UserJDKProxy(
                        //目标接口的实现类
                        new UserDaoImpl()
                )
        );
        userDao.addUser();
        userDao.removeUser();
    }
}

CGLIB动态代理

cglib是针对类进行代理,不局限与接口,它通过实现对指定类通过继承生成一个子类,并覆盖原有方法来实现代理

  1. 首先接口与实现类与之前一致不做更改
  2. 使用CGLIB代理,注意这边导的包已经变成cglib的了
package cn.edu.zucc.blog.CGLIBProxy;

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

import java.lang.reflect.Method;

/**
 * CGLIB代理
 * @author xyj
 */
public class UserCglibProxy implements MethodInterceptor {
    private Object target;
    /**
     * 获取原本调用的实现类
     * 相当于JDK代理当中的构造器
     * @param target 原有实现类
     */
    public Object getInstance(Object target){
        //给代理对象赋值
        this.target=target;
        //创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();
        //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        enhancer.setSuperclass(this.target.getClass());
        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
        enhancer.setCallback(this);
        // 创建动态代理类对象并返回
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //前置操作
        System.out.println("before method : "+method.getName());
        //通过反射调用原有方法
        Object o1 = methodProxy.invokeSuper(o, objects);
        //后置操作
        System.out.println("after method");
        return o1;
    }
}
  1. Test测试方法
package cn.edu.zucc.blog.CGLIBProxy;

import cn.edu.zucc.blog.UserDaoImpl;

public class Test {
    public static void main(String[] args) {
        //动态代理
        UserCglibProxy userCglibProxy = new UserCglibProxy();
        //创建即将被代理的类
        UserDaoImpl userDaoImpl = new UserDaoImpl();
        //获取代理对象
        UserDaoImpl user = (UserDaoImpl) userCglibProxy.getInstance(userDaoImpl);
        //调用方法        
        user.addUser();
        user.removeUser();
    }
}

总结

静态代理太麻烦
JDK通过接口中方法实现,无法代理实体类
CGLIB通过继承的方法创建被代理对象的子类,重写原有方法。final方法无法继承,所以无法被代理
据说CGLIB要比JDK的慢一点,还有待深入研究

你可能感兴趣的:(框架基础,AOP)