一、使用JDK动态代理

基于 jdk 的动态代理需要借助于jdk 中 reflect 包下(java.lang.reflect.Proxy)的 Proxy以及(java.lang.reflect.InvocationHandler) InvacationHandler去生成代理对象。
局限性是这种动态代理只适用于对有接口的类实现动态代理
原理其实是,利用反射机制先生成要被代理对象的同级对象然后对这个同级对象进行增强

1、接口和实现类(代理对象)

  1. public interface UserDao {
  2. public void add();
  3. public void update();
  4. }
  1. package cn.demo1;
  2. public class UserDaoImp implements UserDao {
  3. @Override
  4. public void add() {
  5. System.out.println("this is add....");
  6. }
  7. @Override
  8. public void update() {
  9. System.out.println("this is update....");
  10. }
  11. }

2、动态代理(重点)

  1. package cn.demo1;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. /**
  6. * 使用jdk动态代理,增强方法
  7. * 想使用jdk动态代理,代理对象类必须实现至少一个接口
  8. *
  9. */
  10. //继承InvocationHandler
  11. public class JDKProxy implements InvocationHandler{
  12. private UserDao userDao;//想使用jdk动态代理,代理对象类必须实现至少一个接口
  13. public JDKProxy(UserDao userDao) {
  14. super();
  15. this.userDao = userDao;
  16. }
  17. public UserDao createProxy(){
  18. //利用接口获得一个增强后的代理对象
  19. UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);
  20. return proxy;
  21. }
  22. //调用对象的任何一个方法,都会执行该方法
  23. @Override
  24. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  25. if("add".equals(method.getName())){
  26. System.out.println("这里是add方法的增强部分");
  27. Object result = method.invoke(userDao, args);
  28. }
  29. if("update".equals(method.getName())){
  30. System.out.println("这里是update方法的增强部分");
  31. Object result = method.invoke(userDao, args);
  32. }
  33. return null;
  34. }
  35. }

3、测试

  1. package cn.demo1;
  2. import org.junit.Test;
  3. public class Test1 {
  4. @Test
  5. //不使用动态代理
  6. public void demo1(){
  7. UserDao dao = new UserDaoImp();
  8. dao.add();
  9. dao.update();
  10. }
  11. @Test
  12. public void demo2(){
  13. UserDao userDao = new UserDaoImp();//实例化一个需要增强的对象
  14. UserDao daoProxy = new JDKProxy(userDao).createProxy();//jdk动态代理 返回一个增强之后的对象
  15. daoProxy.add();
  16. }
  17. }

二、使用CGLib代理

JDK动态代理是基于接口的方式,换句话来说就是代理类和目标类都实现同一个接口,那么代理类和目标类的方法名就一样了;CGLib动态代理是代理类去继承目标类,然后重写其中目标类的方法,这样也可以保证代理类拥有目标类的同名方法;

1、代理对象

  1. package cn.demo2;
  2. public class ProductDao {
  3. public void add(){
  4. System.out.println("this is add....");
  5. }
  6. public void update(){
  7. System.out.println("this is update....");
  8. }
  9. }

2、生成代理(重点)

  1. package cn.demo2;
  2. import java.lang.reflect.Method;
  3. import org.springframework.cglib.proxy.Callback;
  4. import org.springframework.cglib.proxy.Enhancer;
  5. import org.springframework.cglib.proxy.MethodProxy;
  6. /**
  7. * CGLib生成代理的机制是继承
  8. */
  9. //继承cglib的MethodInterceptor
  10. public class CGLibProxy implements org.springframework.cglib.proxy.MethodInterceptor{
  11. private ProductDao productDao;
  12. public CGLibProxy(ProductDao productDao) {
  13. super();
  14. this.productDao = productDao;
  15. }
  16. public ProductDao creatCGLibProxy(){
  17. //使用CGLib生成代理
  18. //1、创建核心类
  19. Enhancer enhancer = new Enhancer();
  20. //2、为它设置父类
  21. enhancer.setSuperclass(productDao.getClass());
  22. //3、设置回调
  23. enhancer.setCallback((Callback) this);
  24. return (ProductDao) enhancer.create();
  25. }
  26. @Override
  27. public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  28. if ("add".equals(method.getName())) {
  29. System.out.println("CGLib代理对象add方法的增强部分");
  30. Object result = methodProxy.invokeSuper(proxy, args);
  31. return result;
  32. }
  33. return methodProxy.invokeSuper(proxy, args);
  34. }
  35. }

3、测试

  1. package cn.demo2;
  2. import org.junit.Test;
  3. public class Test2 {
  4. @Test
  5. public void demo1(){
  6. ProductDao productDao = new ProductDao();
  7. ProductDao productDao2 = new CGLibProxy(productDao).creatCGLibProxy();
  8. productDao2.add();
  9. }
  10. }

注意: Spring 的 AOP 的底层用到两种代理机制:

  • JDK 的动态代理 :针对实现了接口的类产生代理.
  • Cglib 的动态代理 :针对没有实现接口的类产生代理. 应用的是底层的字节码增强的技术 生成当前类的子类对象

转载自个人博客:https://fusangjie.club/