• Guice 学习(八)AOP (面向切面的编程)


    Guice的AOP还是非常弱的。眼下只支持方法级别上的,另外灵活性也不是非常高。

    看例如以下演示样例:

    Guice支持AOP的条件是:

    类必须是public或者package (default)
    类不能是final类型的
    方法必须是public,package或者protected
    方法不能使final类型的
    实例必须通过Guice的@Inject注入或者有一个无參数的构造函数
    

    且看演示样例代码

    1、定义接口

    package com.guice.AOP;
    
    import com.google.inject.ImplementedBy;
    
    @ImplementedBy(ServiceImpl.class)
    public interface Service {
        public void sayHello();
    }
    

    2、定义实现类

    package com.guice.AOP;
    
    import com.google.inject.Singleton;
    import com.google.inject.name.Named;
    
    @Singleton
    public class ServiceImpl implements Service {
    
        @Named("log")
        @Override
        public void sayHello() {
            System.out.println(String.format("[%s#%d] execute %s at %d", this.getClass().getSimpleName(), hashCode(), "sayHello", System.nanoTime()));
        }
    }

    3、定义切面

    package com.guice.AOP;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    /**
     *  TODO :自己定义的方法拦截器。用于输出方法的运行时间
     * 
     * @author E468380
     */
    public class LoggerMethodInterceptor implements MethodInterceptor {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            String name = invocation.getMethod().getName();
            long startTime = System.nanoTime();
            System.out.println(String.format("before method[%s] at %s", name, startTime));
    
            Object obj = null;
            try {
                obj = invocation.proceed();// 运行服务
            } finally {
                long endTime = System.nanoTime();
                System.out.println(String.format("after method[%s] at %s, cost(ns):%d", name, endTime, (endTime - startTime)));
            }
            return obj;
        }
    }
    

    4、測试类

    package com.guice.AOP;
    
    import com.google.inject.Binder;
    import com.google.inject.Guice;
    import com.google.inject.Inject;
    import com.google.inject.Injector;
    import com.google.inject.Module;
    import com.google.inject.matcher.Matchers;
    import com.google.inject.name.Names;
    
    public class AopTest {
        @Inject
        private Service service;
    
        public static void main(String[] args) {
            Injector injector = Guice.createInjector(new Module() {
    
                @Override
                public void configure(Binder binder) {
                    binder.bindInterceptor(Matchers.any(), Matchers.annotatedWith(Names.named("log")), new LoggerMethodInterceptor());
                }
            });
            injector.getInstance(AopTest.class).service.sayHello();
            injector.getInstance(AopTest.class).service.sayHello();
            injector.getInstance(AopTest.class).service.sayHello();
        }
    }

    输出结果:

     before method[sayHello] at 18832801981960
     [ServiceImpl$$EnhancerByGuice$$d4244950#1109685565] execute sayHello at 18832817170768
     after method[sayHello] at 18832817378285, cost(ns):15396325
     before method[sayHello] at 18832817542181
     [ServiceImpl$$EnhancerByGuice$$d4244950#1109685565] execute sayHello at 18832817640327
     after method[sayHello] at 18832817781772, cost(ns):239591
     before method[sayHello] at 18832817920651
     [ServiceImpl$$EnhancerByGuice$$d4244950#1109685565] execute sayHello at 18832818013023
     after method[sayHello] at 18832818132657, cost(ns):212006

    关于此结果有几点说明:

    (1)因为使用了AOP我们的服务得到的不再是我们写的服务实现类了,而是一个继承的子类,这个子类应该是在内存中完毕的。

    (2)除了第一次调用比較耗时外(可能guice内部做了比較多的处理)。其他调用事件为0毫秒(我们的服务本身也没做什么事)。

    (3)确实完毕了我们期待的AOP功能。



    5、切面注入依赖

    假设一个切面(拦截器)也须要注入一些依赖怎么办?

    在这里我们声明一个前置服务。输出全部调用的方法名称。

    ①定义接口

    package com.guice.AOP;
    
    import org.aopalliance.intercept.MethodInvocation;
    
    import com.google.inject.ImplementedBy;
    
    @ImplementedBy(BeforeServiceImpl.class)
    public interface BeforeService {
        void before(MethodInvocation invocation);
    }
    

    ②定义实现类

    package com.guice.AOP;
    
    import org.aopalliance.intercept.MethodInvocation;
    
    public class BeforeServiceImpl implements BeforeService {
        @Override
        public void before(MethodInvocation invocation) {
            System.out.println("Before--->" + invocation.getClass().getName());
        }
    }

    ③定义切面

    package com.guice.AOP;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    
    import com.google.inject.Inject;
    
    //这个切面依赖前置服务
    public class AfterMethodIntercepter implements MethodInterceptor {
        @Inject
        private BeforeService beforeService;
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            beforeService.before(invocation);
            Object obj = null;
            try {
                obj = invocation.proceed();
            } finally {
                System.out.println("after--->" + invocation.getClass().getName());
            }
            return obj;
        }
    }

    ④编写測试类

    package com.guice.AOP;
    
    import com.google.inject.Binder;
    import com.google.inject.Guice;
    import com.google.inject.Inject;
    import com.google.inject.Injector;
    import com.google.inject.Module;
    import com.google.inject.matcher.Matchers;
    import com.google.inject.name.Names;
    
    public class AopTest2 {
        @Inject
        private Service service;
    
        public static void main(String[] args) {
            Injector injector = Guice.createInjector(new Module() {
    
                @Override
                public void configure(Binder binder) {
                    AfterMethodIntercepter after = new AfterMethodIntercepter();
                    binder.requestInjection(after);
                    binder.bindInterceptor(Matchers.any(), Matchers.annotatedWith(Names.named("log")), after);
                }
            });
            injector.getInstance(AopTest2.class).service.sayHello();
        }
    
    }

    输出结果:

     Before--->com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation
     [ServiceImpl$$EnhancerByGuice$$618294e9#506575947] execute sayHello at 20140444543338
     after--->com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation
    

    说明
    Binder绑定一个切面的API是:

    com.google.inject.Binder.bindInterceptor(Matcher<? super Class<?

    >>, Matcher<? super Method>, MethodInterceptor...)

    第一个參数是匹配类,第二个參数是匹配方法,第三个数组參数是方法拦截器。也就是说眼下为止Guice只能拦截到方法,然后才做一些切面工作。

    注意

    虽然切面同意注入其依赖,可是这里须要注意的是。假设切面依赖仍然走切面的话那么程序就陷入了死循环,非常久就会堆溢出。
    Guice的AOP还是非常弱的,眼下只支持方法级别上的。另外灵活性也不是非常高。

  • 相关阅读:
    HTML5你必须知道的28个新特性
    localStorage使用总结
    Oracle分页查询排序数据重复问题
    servlet,RMI,webservice之间的区别
    远程通信的几种选择(RPC,Webservice,RMI,JMS的区别)
    几种通讯协议的比较
    http、TCP/IP协议与socket之间的区别
    Oracle修改序列(Sequence)起始值问题
    mybatis开启二级缓存小记
    使用canvas绘制渐变色矩形和使用按键控制人物移动
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7147739.html
Copyright © 2020-2023  润新知