1、什么是代理模式
    为其他对象提供一种代理以控制对这个对象的访问。

    2、为什么使用代理模式
    开闭原则,增加功能。

    3、代理模式实现原理
    代理模式主要包含三个角色:抽象主题角色Subject,被代理角色Proxied,代 理类proxy

    图片1.png

    4、代理模式应用场景
    SpringAOP、日志收集、权限控制、过滤器、RPC远程调用

    5、代理模式的创建方式
    静态代理和动态代理
    理解:自己手写代理类就是静态代理

    6、静态代理(两种实现方式)

    1. //基于接口实现方式
    2. public interface OrderService {
    3. void order();
    4. }
    5. public class OrderServiceImpl implements OrderService {
    6. public void order() {
    7. System.out.println("用户下单操作..");
    8. }
    9. }
    10. public class OrderServiceProxy implements OrderService {
    11. /**
    12. * 代理对象
    13. */
    14. private OrderService proxiedOrderService;
    15. public OrderServiceProxy( OrderService orderService) {
    16. this.proxiedOrderService=orderService;
    17. }
    18. public void order() {
    19. System.out.println("日志收集开始..");
    20. proxiedOrderService.order();
    21. System.out.println("日志收集结束..");
    22. }
    23. }
    24. public class ClientTest {
    25. public static void main(String[] args) {
    26. OrderService orderService = new OrderServiceProxy(new OrderServiceImpl());
    27. orderService.order();
    28. }
    29. }
    30. //接口继承方式实现
    31. public class OrderServiceProxy extends OrderServiceImpl {
    32. public void order() {
    33. System.out.println("日志收集开始..");
    34. super.order();
    35. System.out.println("日志收集结束..");
    36. }
    37. }
    38. public class ClientTest {
    39. public static void main(String[] args) {
    40. OrderService orderService = new OrderServiceProxy();
    41. orderService.order();
    42. }
    43. }

    7、动态代理
    JDK动态代理:
    JDK动态代理所代理的类定要实现某个接口,其底层应用的是java反射实 现的;

    创建的步骤:
    1、创建被代理的接口和类;
    2、实现InvocationHandler接口,对目标接口中声明的所有方 法进行统一处理;
    3、调用Proxy的静态方法,创建代理类并生成相应的代理对 象。

    1. public interface OrderService {
    2. void order();
    3. }
    4. public class OrderServiceImpl implements OrderService {
    5. public void order() {
    6. System.out.println("修改数据库订单操作..");
    7. }
    8. }
    9. public class JdkInvocationHandler implements InvocationHandler {
    10. /**
    11. * 目标代理对象
    12. */
    13. public Object target;
    14. public JdkInvocationHandler(Object target) {
    15. this.target = target;
    16. }
    17. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    18. System.out.println(">>>日志收集开始>>>>");
    19. // 执行代理对象方法
    20. Object reuslt = method.invoke(target, args);
    21. System.out.println(">>>日志收集结束>>>>");
    22. return reuslt;
    23. }
    24. /**
    25. * 获取代理对象接口
    26. *
    27. * @param <T>
    28. * @return
    29. */
    30. public <T> T getProxy() {
    31. return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    32. }
    33. }
    34. //测试
    35. JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(new OrderServiceImpl());
    36. OrderService proxy = jdkInvocationHandler.getProxy();
    37. proxy.order();

    原理分析:
    F24D6D79-18D2-4478-AFEA-A8438CEB850E.png
    1、获取代理的生成的class文件
    System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
    2、使用反编译工具进行反编译
    1.png

    CGLIB动态代理
    JDK动态代理是通过实现接口来实现 的,而CGLIB是通过继承实现类来实现的;其底层是通过ASM字节码框架来动态修改目标类的字节码来实现的,从而CGLI代理类对象实现动态代理效率比Jdk动态代理反射技术效率要高。
    缺点:对于被代理类中的final方法,无法进行代理,因为子类中无法重写final函数
    实现步骤:
    实现MethodInterceptor接口的intercept方法后,所有生成的代理方法都调用这个方法。
    intercept方法的具体参数有
    obj 目标类的实例
    1、 method 目标方法实例(通过反射获取的目标方法实例)
    2、 args 目标方法的参数
    3.、proxy 代理类的实例
    该方法的返回值就是目标方法的返回值。

    1. public class OrderServiceImpl {
    2. public void order() {
    3. System.out.println("用户下单操作..");
    4. }
    5. }
    6. public class CglibMethodInterceptor implements MethodInterceptor {
    7. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    8. System.out.println("<<<<<日志收集开始...>>>>>>>");
    9. Object reuslt = proxy.invokeSuper(obj, args);
    10. System.out.println("<<<<<日志收集结束...>>>>>>>");
    11. return reuslt;
    12. }
    13. }
    14. System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
    15. CglibMethodInterceptor cglibMethodInterceptor = new CglibMethodInterceptor();
    16. Enhancer enhancer = new Enhancer();
    17. // 设置代理类的付类
    18. enhancer.setSuperclass(OrderServiceImpl.class);
    19. // 设置回调对象
    20. enhancer.setCallback(cglibMethodInterceptor);
    21. // 创建代理对象
    22. OrderServiceImpl orderServiceImpl = (OrderServiceImpl) enhancer.create();
    23. orderServiceImpl.order();

    maven依赖

    1. <dependencies>
    2. <dependency>
    3. <groupId>cglib</groupId>
    4. <artifactId>cglib</artifactId>
    5. <version>3.2.12</version>
    6. </dependency>
    7. </dependencies>

    8、深入理解
    自己手写
    思路:
    1.拼接代理类的源代码
    2. 写入到到本地文件中.
    3. 使用JavaCompiler技术将源代码编译成class文件
    4.使用classLoader 加载到内存中.
    5.指明初始化有参数构造函数

    1. public interface OrderService {
    2. public void order() throws Throwable;
    3. }
    4. public class OrderServiceImpl implements OrderService {
    5. public void order() {
    6. System.out.println("数据库订单执行操作");
    7. }
    8. }
    9. public interface MyExtJdkInvocationHandler {
    10. /**
    11. * @param proxy 代理类
    12. * @param method 目标方法
    13. * @param args 参数
    14. * @return
    15. * @throws Throwable
    16. */
    17. public Object invoke(Object proxy, Method method, Object[] args)
    18. throws Throwable;
    19. }
    20. public class MyJdkInvocationHandler implements MyExtJdkInvocationHandler {
    21. /**
    22. * 目标对象 被代理的类 真实访问的类的对象
    23. */
    24. private Object target;
    25. public MyJdkInvocationHandler(Object target) {
    26. this.target = target;
    27. }
    28. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    29. System.out.println("<<<<<<<<<纯手写jdk动态代理日志开始>>>>>>>>>>");
    30. Object result = method.invoke(target, args);// 使用java的反射执行
    31. System.out.println("<<<<<<<<纯手写jdk动态代理结束>>>>>>>>>>");
    32. return result;
    33. }
    34. }
    35. public class MyProxy {
    36. static String rt = "\r\t";
    37. public static Object newProxyInstance(JavaClassLoader javaClassLoader,
    38. Class<?> classInfo,
    39. MyExtJdkInvocationHandler h) {
    40. //1.拼接代理类的源代码
    41. try {
    42. // 1.创建代理类java源码文件,写入到硬盘中..
    43. Method[] methods = classInfo.getMethods();
    44. String proxyClass = "package com.mayikt.ext.proxy;" + rt
    45. + "import java.lang.reflect.Method;" + rt
    46. + "import com.mayikt.ext.proxy.MyExtJdkInvocationHandler;" + rt
    47. + "public class $Proxy0 implements " + classInfo.getName() + "{" + rt
    48. + "MyExtJdkInvocationHandler h;" + rt
    49. + "public $Proxy0(MyExtJdkInvocationHandler h)" + "{" + rt
    50. + "this.h= h;" + rt + "}"
    51. + getMethodString(methods, classInfo) + rt + "}";
    52. // 2. 写入到到本地文件中..
    53. String filename = "d:/$Proxy0.java";
    54. File f = new File(filename);
    55. FileWriter fw = new FileWriter(f);
    56. fw.write(proxyClass);
    57. fw.flush();
    58. fw.close();
    59. // 3. 将源代码编译成class文件
    60. JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    61. StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
    62. Iterable units = fileMgr.getJavaFileObjects(filename);
    63. JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
    64. t.call();
    65. fileMgr.close();
    66. // 4.使用classLoader 加载到内存中..
    67. Class<?> $Proxy0 = javaClassLoader.findClass("$Proxy0");
    68. // 5.指明初始化有参数构造函数
    69. Constructor<?> constructor = $Proxy0.getConstructor(MyExtJdkInvocationHandler.class);
    70. Object o = constructor.newInstance(h);
    71. return o;
    72. } catch (Exception e) {
    73. e.printStackTrace();
    74. }
    75. return null;
    76. }
    77. public static String getMethodString(Method[] methods, Class intf) {
    78. String proxyMe = "";
    79. for (Method method : methods) {
    80. proxyMe += "public void " + method.getName() + "() throws Throwable {" + rt
    81. + "Method md= " + intf.getName() + ".class.getMethod(\"" + method.getName()
    82. + "\",new Class[]{});" + rt
    83. + "this.h.invoke(this,md,null);" + rt + "}" + rt;
    84. }
    85. return proxyMe;
    86. }
    87. public static void main(String[] args) {
    88. newProxyInstance(null, OrderService.class, null);
    89. }
    90. }

    工具类

    1. public class JavaClassLoader extends ClassLoader {
    2. private File classPathFile;
    3. public JavaClassLoader(){
    4. // String classPath=JavaClassLoader.class.getResource("").getPath();
    5. String classPath="D:\\";
    6. this.classPathFile=new File(classPath);
    7. }
    8. @Override
    9. public Class<?> findClass(String name) throws ClassNotFoundException {
    10. String className= JavaClassLoader.class.getPackage().getName()+"."+name;
    11. if(classPathFile!=null){
    12. File classFile=new File(classPathFile,name.replaceAll("\\.","/")+".class");
    13. if(classFile.exists()){
    14. FileInputStream in=null;
    15. ByteArrayOutputStream out=null;
    16. try {
    17. in=new FileInputStream(classFile);
    18. out=new ByteArrayOutputStream();
    19. byte[] buff=new byte[1024];
    20. int len;
    21. while ((len=in.read(buff))!=-1){
    22. out.write(buff,0,len);
    23. }
    24. return defineClass(className,out.toByteArray(),0,out.size());
    25. }catch (Exception e){
    26. e.printStackTrace();
    27. }finally {
    28. if(in!=null){
    29. try {
    30. in.close();
    31. } catch (IOException e) {
    32. e.printStackTrace();
    33. }
    34. }
    35. if(out!=null){
    36. try {
    37. out.close();
    38. } catch (IOException e) {
    39. e.printStackTrace();
    40. }
    41. }
    42. }
    43. }
    44. }
    45. return null;
    46. }
    47. }

    java反射

    1. public static void main(String[] args) {
    2. MemberServiceImpl memberService = new MemberServiceImpl();
    3. Class member= memberService.getClass();
    4. Annotation[] annotations=member.getAnnotations();
    5. for(int i=0;i<annotations.length;i++){
    6. //org.springframework.web.bind.annotation.RestController
    7. System.out.println(annotations[i].annotationType().getName());
    8. //RestController
    9. System.out.println(annotations[i].annotationType().getSimpleName());
    10. }
    11. }
    12. @RestController
    13. public class MemberServiceImpl {
    14. }