• 模仿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();
        }
    }
    复制代码
    大致的流程就是:传入要被代理的类和自定义的注解类,运用反射获取注解类里方法上的注解属性的值,然后进行比对,再进行相应的操作。
  • 相关阅读:
    2019 春第1次课程设计实验报告
    2019春第十二周作业
    2019春第十一周作业
    2019春第十周作业
    关于Vmvare虚拟机中Linux系统不能全屏的问题
    My algorithmic road
    段错误
    python人生如初见之初见yield
    网络爬虫requests-bs4-re-1
    The First Python man in Github
  • 原文地址:https://www.cnblogs.com/shizhijie/p/8428834.html
Copyright © 2020-2023  润新知