第10章 反射机制 - 动态代理1

优质
小牛编辑
133浏览
2023-12-01

系列阅读

1. 概述

在运行时,动态创建一组指定的接口的实现类对象(代理对象)!

代理是实现AOP(面向切面编程)的核心和关键技术,动态代理的用途与装饰模式很相似,就是为了对某个对象进行增强。所有使用装饰者模式的案例都可以使用动态代理来替换。

代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。

举例:春季回家买票让人代买

动态代理:在程序运行过程中产生的这个对象

而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理

2. 工作原理

  • client调用代理
  • 代理的构造方法接收一个invocationhandler参数
  • client调用代理的各个方法,代理的各个方法会把调用请求转发给invocationhandler
  • invocationhandler通过invoke()方法把调用请求分发给目标对象的各个方法

1、在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib

2、Proxy类中的方法创建动态代理类对象

  1. public static Object newProxyInstance(
  2. ClassLoader loader,
  3. Class<?>[]interfaces,
  4. InvocationHandler h)

返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。最终会调用InvocationHandler的方法

3、InvocationHandler

  1. Object invoke(Object proxy,Method method,Object[] args)

在代理实例上处理方法调用并返回结果。

4、Proxy类中创建动态代理对象的方法的三个参数

  • ClassLoader对象

    定义了由哪个ClassLoader对象来对生成的代理对象进行加载

  • Interface对象的数组

    表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了

  • InvocationHandler对象

    表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke 方法来进行调用。

5、InvocationHandler接口中invoke()方法的三个参数:

  • Object proxy:代表动态代理对象
  • Method method:代表正在执行的方法
  • Object[] args:代表调用目标方法时传入的实参

6、Proxy.newProxyInstance()

创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号

3. 动态代理的实现

  1. package cn.itcast_06;
  2. /*
  3. * 用户操作接口
  4. */
  5. public interface UserDao {
  6. public abstract void add();
  7. public abstract void delete();
  8. public abstract void update();
  9. public abstract void find();
  10. }
  1. package cn.itcast_06;
  2. public interface StudentDao {
  3. public abstract void login();
  4. public abstract void regist();
  5. }
  1. package cn.itcast_06;
  2. public class UserDaoImpl implements UserDao {
  3. @Override
  4. public void add() {
  5. System.out.println("添加功能");
  6. }
  7. @Override
  8. public void delete() {
  9. System.out.println("删除功能");
  10. }
  11. @Override
  12. public void update() {
  13. System.out.println("修改功能");
  14. }
  15. @Override
  16. public void find() {
  17. System.out.println("查找功能");
  18. }
  19. }
  1. package cn.itcast_06;
  2. public class StudentDaoImpl implements StudentDao {
  3. @Override
  4. public void login() {
  5. System.out.println("登录功能");
  6. }
  7. @Override
  8. public void regist() {
  9. System.out.println("注册功能");
  10. }
  11. }
  1. package cn.itcast_06;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. public class MyInvocationHandler implements InvocationHandler {
  5. private Object target; // 目标对象
  6. public MyInvocationHandler(Object target) {
  7. this.target = target;
  8. }
  9. @Override
  10. public Object invoke(Object proxy, Method method, Object[] args)
  11. throws Throwable {
  12. System.out.println("权限校验");
  13. Object result = method.invoke(target, args);
  14. System.out.println("日志记录");
  15. return result; // 返回的是代理对象
  16. }
  17. }
  1. package cn.itcast_06;
  2. import java.lang.reflect.Proxy;
  3. public class Test {
  4. public static void main(String[] args) {
  5. UserDao ud = new UserDaoImpl();
  6. ud.add();
  7. ud.delete();
  8. ud.update();
  9. ud.find();
  10. System.out.println("-----------");
  11. // 我们要创建一个动态代理对象
  12. // Proxy类中有一个方法可以创建动态代理对象
  13. // public static Object newProxyInstance(ClassLoader loader,Class<?>[]
  14. // interfaces,InvocationHandler h)
  15. // 我准备对ud对象做一个代理对象
  16. MyInvocationHandler handler = new MyInvocationHandler(ud);
  17. UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass()
  18. .getClassLoader(), ud.getClass().getInterfaces(), handler);
  19. proxy.add();
  20. proxy.delete();
  21. proxy.update();
  22. proxy.find();
  23. System.out.println("-----------");
  24. StudentDao sd = new StudentDaoImpl();
  25. MyInvocationHandler handler2 = new MyInvocationHandler(sd);
  26. StudentDao proxy2 = (StudentDao) Proxy.newProxyInstance(sd.getClass()
  27. .getClassLoader(), sd.getClass().getInterfaces(), handler2);
  28. proxy2.login();
  29. proxy2.regist();
  30. }
  31. }

4. Spring原理

  1. public class ProxyFactoryBean {
  2. private Object mTarget;
  3. private Advice mAdvice;
  4. public Object getProxy(){
  5. Object proxy = Proxy.newProxyInstance(
  6. mTarget.getClass().getClassLoader(),
  7. mTarget.getClass().getInterfaces(),
  8. mHandler
  9. );
  10. return proxy;
  11. }
  12. private InvocationHandler mHandler = new InvocationHandler() {
  13. @Override
  14. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  15. mAdvice.beforeMethod(method);
  16. Object result = method.invoke(mTarget, args);
  17. mAdvice.afterMethod(method);
  18. return result;
  19. }
  20. };
  21. public void setTarget(Object target) {
  22. mTarget = target;
  23. }
  24. public void setAdvice(Advice advice) {
  25. mAdvice = advice;
  26. }
  27. public Object getTarget() {
  28. return mTarget;
  29. }
  30. public Advice getAdvice() {
  31. return mAdvice;
  32. }
  33. }
  34. public class BeanFactory {
  35. Properties mProperties = new Properties();
  36. public BeanFactory(InputStream in){
  37. try {
  38. mProperties.load(in);
  39. } catch (IOException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. public Object getBean(String name){
  44. String classname = mProperties.getProperty(name);
  45. Object bean = null;
  46. try {
  47. Class clazz = Class.forName(classname);
  48. bean = clazz.newInstance();
  49. } catch (Exception e) {
  50. e.printStackTrace();
  51. }
  52. if (bean instanceof ProxyFactoryBean){
  53. Object proxy = null;
  54. ProxyFactoryBean factoryBean = (ProxyFactoryBean) bean;
  55. Advice advice = null;
  56. try {
  57. advice = (Advice) Class.forName(mProperties.getProperty(name+".advice")).newInstance();
  58. Object target = Class.forName(mProperties.getProperty(name+".target")).newInstance();
  59. factoryBean.setAdvice(advice);
  60. factoryBean.setTarget(target);
  61. proxy = factoryBean.getProxy();
  62. } catch (Exception e) {
  63. e.printStackTrace();
  64. }
  65. return proxy;
  66. }
  67. return bean;
  68. }
  69. }
  1. public interface Advice {
  2. void beforeMethod(Method method);
  3. void afterMethod(Method method);
  4. }
  1. public class AopFrameworkTest {
  2. public static void main(String[] args) throws Exception {
  3. InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");
  4. Object bean = new BeanFactory(ips).getBean("xxx");
  5. System.out.println(bean.getClass().getName());
  6. ((Collection)bean).clear();
  7. }
  8. }