码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2018-02-08 00:23:55      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:结构   turn   操作   new   lambda   react   lam   理论   default   

入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的功能,利用注解搭建自己的框架。

标签:结构   turn   操作   new   lambda   react   lam   理论   default   

原文地址:https://www.cnblogs.com/shizhijie/p/8428834.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!