模仿spring-aop的功能,利用注解搭建自己的框架。

Posted 勿忘初心-Lislie杰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模仿spring-aop的功能,利用注解搭建自己的框架。相关的知识,希望对你有一定的参考价值。

入JAVA坑7月有余,也尝试自己手动搭建框架,最近对spring aop的这种切面很着迷,为此记录下自己目前搭出来的小小的demo,后续有时间也会继续改进自己的demo。望大神们不吝赐教。

  主要还是运用反射和java自带的代理类。理论知识就不说了,因为我目前也不是很清楚,避免误导,还是避而不谈吧。好了,直接根据代码撸吧。

  结构:

  

  

接口 
Person.java
public interface Person {
    void say();
}

 

接口实现类

Man.java
复制代码
public class Man implements Person {
    @Override
    public void say() {
        System.out.println("男人say:....");
    }
}
复制代码

 

自定义注解

@interface WaterAOP
复制代码
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Documented
public @interface WaterAOP {
    enum METHOD{before,after,afterthrowing}
    METHOD method() default METHOD.after;
    String Name() default "类全名";
}
复制代码

自定义注解类

WaterLog.java
复制代码
public class WaterLog {

    @WaterAOP(Name = "com.water.aop.attempt3.Man",method = WaterAOP.METHOD.after)
    public void afterAction(){
        System.out.println("后置行为");
    }
    @WaterAOP(Name = "com.water.aop.attempt3.Man",method = WaterAOP.METHOD.before)
    public void beforeAction(){
        System.out.println("前置行为");
    }
}
复制代码

实现自定义代理类(就是在

Proxy.newProxyInstance()方法的第三个参数里做手脚。用了java8的lambda表达式。

  ProxyFactory.java

复制代码
public class ProxyFactory {
    // 维持一个实现接口的被代理的对象,后面改为对象组,由浅入深
    private Person person;
    private WaterLog waterLog;
    private Method beforeMethod=null,afterMethod=null;
    public ProxyFactory(Person person,WaterLog waterLog){
        this.person=person;
        this.waterLog=waterLog;
    }
    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
                person.getClass().getClassLoader(),
                person.getClass().getInterfaces(),
//                第一个参数就是代理者,如果你想对代理者做一些操作可以使用这个参数;
//                第二个就是被执行的方法,
//                第三个是执行该方法所需的参数。
                (Object proxyObj, Method method,Object[] args)->{
                    //如果没有传入aop 直接返回空
                    if(waterLog==null){
                        return null;
                    }
                    Class aop=waterLog.getClass();
                    Class c = person.getClass();
                    // 获取aop类的方法的注解并赋给自定义的一些变量,下面根据这些变量是否有值来确定是否有注解
                    getAnnotation(aop,c);
                    if(beforeMethod!=null){
                        beforeMethod.invoke(waterLog);
                    }
                    // 代理对象执行方法并且获得返回值
                    Object returnValue=method.invoke(person,args);
                    if(afterMethod!=null){
                        afterMethod.invoke(waterLog);
                    }
                    return returnValue;
                }
        );
    }
    private void getAnnotation(Class aop,Class proxy){
        //如果有AOP的类
        if(waterLog!=null){
            // 获取切面类所有的方法
            Method[] methodsAOP=aop.getMethods();
            // 如果切入的日志类的方法不为空
            if(methodsAOP!=null){
                for(Method logMethod:methodsAOP){
                    // 取得WaterLog类的方法上WaterAOP注解
                    WaterAOP waterAOP=logMethod.getAnnotation(WaterAOP.class);
                    if(waterAOP!=null) {
                        // 如果AOP上的注解与传入的类名一致
                        if (proxy.toString().substring(6).equals(waterAOP.Name())) {
                            if (waterAOP.method() == WaterAOP.METHOD.before) {
                                // 赋值 ,后面再执行
                                beforeMethod=logMethod;
                            }else if(waterAOP.method() == WaterAOP.METHOD.after){
                                afterMethod=logMethod;
                            }
                        }
                    }
                }
            }
        }
    }

}

zhuanzi https://www.cnblogs.com/water-zmh/p/8427877.html
复制代码

测试类

Test.java (junit是个测试包,也可以直接用main方法)

复制代码
public class Test {
    @org.junit.Test
    public void waterAOP(){
        Person person=new Man();
        Person proxyPerson=(Person) new ProxyFactory(person,new WaterLog()).getProxyInstance();
        proxyPerson.say();
    }
}
复制代码

 

大致的流程就是:传入要被代理的类和自定义的注解类,运用反射获取注解类里方法上的注解属性的值,然后进行比对,再进行相应的操作。

以上是关于模仿spring-aop的功能,利用注解搭建自己的框架。的主要内容,如果未能解决你的问题,请参考以下文章

深入理解spring-AOP注解的底层实现原理

注解实现的spring-aop

Spring-AOP注解开发

Spring-AOP学习笔记-04 注解配置

spring-aop的简单实例注解版

看了同事写的代码,我竟然开始默默的模仿了。。。