Java通过JDK动态代理简单的实现一个AOP

首先说一下,因为自己还没有去研读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(); } } } } }

自己本身也是个新人,所以望大佬们见谅,代码并没有写得完美,更像是演示一这个功能,但是核心思想应该是差不多的,而且越简单可以让同学理解更快,我们学习的更应该是思想!

 

上一篇:Java多态性


下一篇:【Java基础】方法重写为什么不能抛出比父类更多的异常?