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

2019-10-13 11:04:41来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

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(); } } } } }

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

 


原文链接:https://www.cnblogs.com/junalncer/p/11663113.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:MyBatis的配置与使用(增,删,改,查)

下一篇:Java自学-异常处理 Exception