所谓动态代理其实就是运行期,动态的增强了目标对象的执行方法。
image.png

jdk的动态代理

JDK的动态代理是按照接口代理的。接口中没有的方法,无法代理。
其实JDK动态代理就是JDK自己帮我们实现类那个静态代理中的代理类。

jdk的Proxy类提供了一个静态方法,用于获取动态代理类的实例。
这个静态方法:
static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
返回目标类的一个代理对象实例。
参数1:目标类的类加载器
参数2:目标类实现的所有接口的数组
参数3:增强处理器,需要我们自己实现

例子:准备一个动态代理工厂,用于功能增强(用于给某个方法前后添加其他方法)

  1. package com.quail.proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. public class ProxyFactory {
  6. private Object target;//被代理的目标对象
  7. // 使用构成方法初始化目标对象
  8. public ProxyFactory(Object target){
  9. this.target = target;
  10. }
  11. // 返回代理对象
  12. public Object getObject(){
  13. // 传入相应的参数
  14. Class clazz = target.getClass();
  15. // 使用匿名内部类直接实现InvocationHandler
  16. Object obj = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
  17. // proxy:代理实例;method:被增强的方法;args:被增强的方法的参数列表;return:被增强方法的返回值
  18. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  19. System.out.println("目标方法前功能增强");
  20. Object result = method.invoke(target, args);
  21. System.out.println("目标方法后功能增强");
  22. return result;
  23. }
  24. });
  25. return obj;
  26. }
  27. }

实体类和接口:

  1. public interface UserDao {
  2. int save(String name);
  3. }
  4. public class UserDaoImpl implements UserDao {
  5. public int save(String name) {
  6. System.out.println("我的名字是:"+name);
  7. return 1;
  8. }
  9. }

测试类:

  1. package com.quail.test;
  2. import com.quail.dao.UserDao;
  3. import com.quail.dao.impl.UserDaoImpl;
  4. import com.quail.proxy.ProxyFactory;
  5. import org.junit.Test;
  6. public class ProxyTest {
  7. @Test
  8. public void testJDKProxy(){
  9. // 准备目标对象
  10. UserDaoImpl userDao = new UserDaoImpl();
  11. // 使用工厂创建代理对象
  12. ProxyFactory proxyFactory = new ProxyFactory(userDao);
  13. // 获取代理对象,必须是接口类型
  14. UserDao dao = (UserDao) proxyFactory.getObject();
  15. dao.save("quail");
  16. }
  17. }

执行结果:image.png

Spring的动态代理

Spring实现动态代理其实通过两种方式:

  • 一种是JDK的动态代理方式,使用Proxy类的静态方法newProxyInstance()
  • 另一种是CGLib包的动态代理方式。这种方式可以代理接口中没有的方法。原因:CGLib增强一个方法是使用继承实现的。CGLib可以看做是JDK动态proxy的一个升级,区别:不光可以代理有接口的对象,还可以代理没有接口的对象。 ```java package com.quail.proxy;

import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.InvocationHandler;

import java.lang.reflect.Method;

public class CGLibProxyFactory { private Object target;//目标对象

  1. public CGLibProxyFactory(Object target){this.target=target;}
  2. public Object getObject(){
  3. // 直接创建一个增强器对象
  4. Enhancer enhancer = new Enhancer();
  5. // 设置父类类型
  6. enhancer.setSuperclass(target.getClass());
  7. // 设置处理器
  8. enhancer.setCallback(new InvocationHandler() {
  9. public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
  10. System.out.println("目标方法前的增强");
  11. Object invoke = method.invoke(target, objects);
  12. System.out.println("目标方法后的增强");
  13. return invoke;
  14. }
  15. });
  16. return enhancer.create();//创建代理对象并且返回
  17. }

}

```