首先说一下,因为自己还没有去研读spring的AOP的源码,只是大致知道其功能,便想着自己先手动实现一个先看看,觉得这样以后研读源码的时候会收获更多!
实现:做一个在添加注解的方法执行之前,可以先执行另一个方法。类似AOP(@Brfore),不明白的同学可以去百度下,这边只做一个简单的现实。
首先准备一个接口IEat,作为你要做的事情比如,eat():
public interface IEat { void eat(); }
然后两个类去实现这个接口,一个是我们的主要方法(原有不可变动的功能,这边自定义了一个@DoPre注解类似于@Before)Eat,一个是我们的代理类MyProxy,代理类还需去实现InvocationHandler这个接口,并且将cook()方法放在invoker()方法前(这个方法不清楚的同学可以去百度下,他在这里是实现执行Eat中的eat()方法,这样就相当于我前置了我需要添加的方法,吃之前得先做饭):
public class Eat implements IEat { @DoPre @Override public void eat() { System.out.println("eateateat"); } }
public class MyProxy implements InvocationHandler, IEat { private Object object; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { cook(); method.invoke(object); return null; } public MyProxy(Object object) { this.object = object; } @Override public void eat() { } private void cook() { System.out.println("cooking"); } }
@DoPre注解没有具体做啥,只是作为一个标记,记得加@Retention(RetentionPolicy.RUNTIME)是指运行时能通过反射找到注解:
@Retention(RetentionPolicy.RUNTIME) public @interface DoPre {}
最后main方法作为启动器,初始化init()方法负责扫面当前包下的带有这个@DoPre注解的方法,这边的初始化写的很简单,没有去遍历其他的包和子包,一切求简,可以自己优化很多地方:
public class Test { public static IEat eat; //start public static void main(String[] args) { init(); eat.eat(); } private static void init() { Class clazz = Test.class; String packagePath = clazz.getResource("").getPath(); String packagename = clazz.getPackage().getName(); File file = new File(packagePath); if (file.isDirectory()) { File[] files = file.listFiles(); assert files != null; for (File file1 : files) { try { StringBuilder stringBuilder = new StringBuilder(packagename); stringBuilder.append(".").append(file1.getName()); String s = stringBuilder.toString().replace(".class", ""); Class clazz1 = Class.forName(s); Method[] methods = clazz1.getMethods(); for (Method method : methods) { Annotation[] annotations = method.getDeclaredAnnotations(); for (Annotation annotation : annotations) { //找到注解方法 if (annotation.toString().contains("DoPre")) { //传入被代理的实例clazz1.newInstance() IEat proxy = (IEat) Proxy.newProxyInstance(Test.class.getClassLoader(), MyProxy.class.getInterfaces(), new MyProxy(clazz1.newInstance())); //注入对象 eat = proxy; } } } } catch (Exception e) { e.printStackTrace(); } } } } }
自己本身也是个新人,所以望大佬们见谅,代码并没有写得完美,更像是演示一这个功能,但是核心思想应该是差不多的,而且越简单可以让同学理解更快,我们学习的更应该是思想!
原文地址:https://www.cnblogs.com/junalncer/p/11663113.html
时间: 2024-10-23 04:55:33