小白一步步实现SSM框架之AOP(自己实现)
系列文章:
技术小白学习SSM框架(Spring、SpringMVC、MyBatis)
小白一步步实现SSM框架之IOC(自己实现)
小白一步步实现SSM框架之MYBATIS( 存储过程)
AOP实现原理:通过学习IOC和AOP,其中最重要的一个框架中需要加入反射的
学习原理
-
能更好的掌握Spring的使用。
-
能进行对Spring功能更好的扩展及其衍生。
-
一个好的框架涉及到的技术和知识全面,可以对基础知识能有更好的巩固和理解。
-
学习一个框架也为自己开发框架提供很多借鉴的地方。
一、反射生成JDK动态代理
(一)JDK动态代理原理
Proxy两个方法创建动态代理类和动态代理实例
java 17 查找网站
Overview (Java SE 17 & JDK 17) (oracle.com)
-
创建动态代理类
已经过时了,但是还可以使用
@Deprecated public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException
参数分别对应动态代理的class对象,代理类实现interfaces多个接口
-
动态代理实例
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
多了一个InvocationHandler接口,这个是接口需要实现的invoke()方法,可以看到来了invoke。
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
(二)JDK动态代理代码实现
-
创建Person接口
package reflectjdkExample;
public interface Person {void walk();void sayHello(String name);
}
- 创建MyInvocationHandler类
步骤一: 加入InvocationHandler 接口,实现 invoke 方法。
步骤二:以上两种方式的实现,转为Person接口调用两个方法。
package reflectjdkExample;import java.lang.reflect.*;
//import java.util.Arrays;public class MyInvocationHandler implements InvocationHandler {/*** 当执行动态代理对象的所有方法时候,都会被替换成invoke()方法执行* @param proxy 动态代理对象* @param method 执行方法* @param args 传入参数* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法是什么:"+method);if (args!=null){System.out.println("参数是什么:");// JDK10 引入了var,会自动推断出类型。如果你用的是JDK8 var 替换成 Object ,我用的是JDK17 。for (var val:args){System.out.println(val);}// Arrays.stream(args).toList().forEach(System.out::println);}else{System.out.println("没有参数");}return null;}public static void main(String[] args) throws NoSuchMethodException,InvocationTargetException, InstantiationException, IllegalAccessException {/** 简化实现版本* var p=(Person) Proxy.newProxyInstance(* Person.class.getClassLoader()* ,new Class[]{Person.class},* handler);*/// 获取代理类Class proxyClass=Proxy.getProxyClass(Person.class.getClassLoader(),Person.class);// 获取构造方法Constructor ctor=proxyClass.getConstructor(InvocationHandler.class);// 创建代理对象实例var p=(Person) ctor.newInstance(new MyInvocationHandler());p.walk();p.sayHello("sky");}
}
输出结果
方法是什么:public abstract void reflectjdkExample.Person.walk() 没有参数 方法是什么:public abstract void reflectjdkExample.Person.sayHello(java.lang.String) 参数是什么: sky
二、动态代理+AOP
为了解决的问题是把相同的代码抽取出来,只需要修改一处代码即可,提供代码的维护性。
AOP代理的方法实现步骤:
步骤一:动态代理增加的通用方法
步骤二:回调目标对象的方法
步骤三:动态代理增加的通用方法
-
加入Person接口的 FlyPerson 类
package reflectjdkExample;public class FlyPerson implements Person{@Overridepublic void walk() {System.out.println("走的最快");}@Overridepublic void sayHello(String name) {System.out.println("hello," + name);} }
-
加入PersonUtil 拦截方法类********* 这边就是把通用的方法给抽取出来了,例如每次进行网页跳转的时候进行身份校验。
package reflectjdkExample;public class PersonUtil {public void method1(){System.out.println("======method1拦截======");}public void method2(){System.out.println("======method2拦截======");} }
-
设置MyProxyFactory代理工厂
设置代理的目标,1.创建MyInvokationHandler对象,2. 代理目标设置,3.创建并返回动态代理
package reflectjdkExample;import java.lang.reflect.Proxy;public class MyProxyFactory {public static Object getProxy(Object target) {var handler = new MyInvokationHandler();handler.setTarget(target);return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);} }
-
MyInvokationHandler类
第一步:实现InvocationHandler 接口的 invoke方法,1创建拦截器,2执行拦截器method1方法,3调用目标对象的方法(具体可以看小白一步步实现SSM框架之IOC(自己实现)文章https://blog.csdn.net/weixin_45631815/article/details/140475054?spm=1001.2014.3001.5501 反射知识点),4执行拦截器method2方法,5 返回调用方法的结果。
第二步: main 静态方法实现,1创建FlyPerson对象,2 返回动态代理对象并转为Person接口,3.执行接口的sayHello 和 walk方法。
package reflectjdkExample;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;public class MyInvokationHandler implements InvocationHandler {private Object target;public void setTarget(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {PersonUtil personUtil = new PersonUtil();personUtil.method1();// 调用目标对象的方法Object result = method.invoke(target, args);personUtil.method2();return result;}public static void main(String[] args) {FlyPerson flyPerson = new FlyPerson();Person person = (Person) MyProxyFactory.getProxy(flyPerson);person.sayHello("sky");person.walk();} }
输出
======method1拦截======hello,sky======method2拦截============method1拦截======走的最快======method2拦截======
三、总结
动态代理+AOP实现,可以解决的是相同的代码抽取。IOC解决了解耦,减少了new 对象。后期会增加IOC和AOP两大功能的结合起来,以及其他的细节功能的增加。
目前准备的是自己手动实现框架形式学习Spring原理,学习好原理之后在应用。
我同时也会遵循(一个好的框架涉及到的技术和知识全面,可以对基础知识能有更好的巩固和理解 )原则。
学习Spring源码资料推荐:
mini-spring