静态代理之AspectJ编译织入

前面两篇文章都是说的在代码运行时动态的生成class文件达到动态代理的目的,那我们现在回到静态代理,静态代理唯一的缺点就是我们需要对每一个方法编写我们的代理逻辑,造成了工作的繁琐和复杂。AspectJ就是为了解决这个问题,在编译成class字节码的时候在方法周围加上业务逻辑。复杂的工作由特定的编译器帮我们做。

AOP有切面(Aspect)、连接点(joinpoint)、通知(advice)、切入点(Pointcut)、目标对象(target)等概念,这里不详细介绍这些概念.

AspectJ的使用

如何做ASpectj开发,这里使用的是maven插件:

 


                org.codehaus.mojo
                aspectj-maven-plugin
                1.5
                
                    
                        
                            compile
                            test-compile
                        
                    
                
                
                    1.6
                    1.6
                    UTF-8
                    1.6
                    true
                    true
                
            

然后编写Aspectj的文件.可以编写.ajc文件,或者使用java文件也可以:

 

//表示对实现了Mtrace接口的类,并且参数数Integer 同时方法中有@RequestMapping 注解的方法插入代理
    @Pointcut("execution(* com.meituan.deploy.Mtrace+.*(java.lang.Integer)) && @annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void zhiru2() {
 
    }
    @Before(value = "zhiru2()")//前面植入
    public void doBeforeTask2(JoinPoint point) {
        //方法调用前植入
        System.out.println("=========BEFORE=========");
    }
 
    @After("zhiru2()")//后面植入
    public void after(JoinPoint point) {
    //方法调用后植入
        System.out.println("===========AFTER=======");
    }
        @AfterThrowing("zhiru2()")
    public void afterthrowing(JoinPoint point) {
        System.out.println("===========throwing=======");
    }
    @AfterReturning("zhiru2()")
    public void afterRutuen(JoinPoint point) {
        System.out.println("===========return=======");
    }

AspectJ的原理分析

反编译过后得到的java代码如下:

 

@RequestMapping({"/hello"})
    public ModelAndView helloMyMethodName(Integer name) throws SQLException {
        JoinPoint var2 = Factory.makeJP(ajc$tjp_0, this, this, name);
 
        Object var7;
        try {
            Object var5;
            try {
                //调用before
                Aspectj.aspectOf().doBeforeTask2(var2);
                System.out.println(name);
                Util.report("xiezhaodong");
                var5 = null;
            } catch (Throwable var8) {
                Aspectj.aspectOf().after(var2);
                throw var8;
            }
            //调用after
            Aspectj.aspectOf().after(var2);
            var7 = var5;
        } catch (Throwable var9) {
            //调用抛出异常
            Aspectj.aspectOf().afterthrowing(var2);
            throw var9;
        }
        //调用return
        Aspectj.aspectOf().afterRutuen(var2);
        return (ModelAndView)var7;
    }
 
    @RequestMapping({"/hello2"})
    public ModelAndView helloMyMethodName222(String name) throws SQLException {
        return new ModelAndView("hello", "name", name);
}

上面两个方法都实现了@ RequestMapping注解,类也实现类Mtrace接口。但是因为传入参数的类型不同,所以只有第一个方法被织入了代理的方法,在真正的方法快周围分表调用了beforeafterafterThrowingafterRutnrn等方法。Aspectj简单的原理就是这样.更加深入的原理解析暂时就不做了。

小结

  • Aspectj并不是动态的在运行时生成代理类,而是在编译的时候就植入代码到class文件
  • 由于是静态织入的,所以性能相对来说比较好
  • Aspectj不受类的特殊限制,不管方法是private、或者static、或者final的,都可以代理
  • Aspectj不会代理除了限定方法之外任何其他诸如toString(),clone()等方法



 

你可能感兴趣的:(java基础进阶)