• spring源码剖析(五)利用AOP实现自定义Spring注解


     

    spring源码剖析(五)利用AOP实现自定义Spring注解

    前段时间在朋友的带动下,入门了LOL,由于有时候自制力不是很强,平时没什么活动,所以就经常在无聊的时候打机,连续几个月,偶尔还通宵了,游戏卸载了两次,但是终究还是装上去了,突然觉得自己好傻逼,卸载了后又去下载安装。。。

    前几天,一个年纪比我小的朋友,聊天中我问,你平时的业余时间有什么兴趣爱好么,然而回答让我比较吃惊,因为平时觉得周围的人的业余生活男的很多就是打游戏,女的很多都是看电视剧。直接和我说,玩游戏是在浪费青春。听到这句话的时候,忽然觉得自己好惭愧,也同时很佩服这类人,觉悟很大,所以自己也就好好收拾一下心态吧,走回学习的旅程。

            话题好像扯远了,抱歉抱歉,扯回来哈,关于AOP使用自定义spring 的注解的话个人觉得还是比较简单的,无非就是通过AOP的面向切面功能,在指定的代码位置织入我们想要的代码,通过参数的形式传递给切面处理程序,然后执行解析,解析完毕后我们就可以做我们想要的操作啦, 例如通过BeanDefinitionVisitor修改Spring容器里面的Bean对象,或者发起其他的调用,通知等。下面举个例子,通过AOP的形式定义注解来,然后通过注解记录我们的日志信息。

    java注解简单介绍

    java 的注解的使用比较简单,如果没有了解的朋友可以去看看一些写的比较好的博客先去学习下,网上写的很好的博客有很多,我重新阐述了,推荐地址:注解(Annotation)自定义注解入门     以及  注解(Annotation)--注解处理器
     
     
     

    AOP的简单介绍

    AOP基本概念

    • 切面(Aspect) :通知和切入点共同组成了切面,时间、地点和要发生的“故事”。
      连接点(Joinpoint) :程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。
      通知(Advice) :通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。
      切入点(Pointcut) :通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称。
      目标对象(Target Object) :即被通知的对象。
      AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理;反之,采用CGLIB代理。
      织入(Weaving)把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:
      1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才能做到,例如AspectJ的织入编译器;
      2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码;
      3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理是使用了JDK的动态代理。
     

    AOP通知类型

     
    @Before 前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。
    @After 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
    @AfterReturning 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。
    @Around 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。
    @AfterThrowing 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。
     


    自定义Spring注解实现

    定义注解有好几种实现方式,有使用aop实现的,也有使用拦截器实现的,实现的话有可能各自有的优缺点,不过总的来说,还是推荐使用aop方式实现。

    定义注解类

    [java] view plain copy
     
    1. /* 
    2.  * Copyright 2002-2013 the original author or authors. 
    3.  * 
    4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
    5.  * you may not use this file except in compliance with the License. 
    6.  * You may obtain a copy of the License at 
    7.  * 
    8.  * http://www.apache.org/licenses/LICENSE-2.0 
    9.  * 
    10.  * Unless required by applicable law or agreed to in writing, software 
    11.  * distributed under the License is distributed on an "AS IS" BASIS, 
    12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    13.  * See the License for the specific language governing permissions and 
    14.  * limitations under the License. 
    15.  */  
    16.   
    17. package net.itaem.annotation;  
    18.   
    19. import java.lang.annotation.Documented;  
    20. import java.lang.annotation.ElementType;  
    21. import java.lang.annotation.Retention;  
    22. import java.lang.annotation.RetentionPolicy;  
    23. import java.lang.annotation.Target;  
    24.   
    25.   
    26. /** 
    27.  * 说明: 
    28.  * 定义日志注解 
    29.  *  
    30.  * @author Fighter168 
    31.  * @date 2016-04-17 
    32.  */  
    33. @Target(ElementType.METHOD)  
    34. @Retention(RetentionPolicy.RUNTIME)  
    35. @Documented  
    36. public @interface FileLog {  
    37.       
    38.     String value() default "日志记录开始";  
    39.       
    40. }  


    定义注解的处理程序

    [java] view plain copy
     
    1. /* 
    2.  * Copyright 2002-2013 the original author or authors. 
    3.  * 
    4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
    5.  * you may not use this file except in compliance with the License. 
    6.  * You may obtain a copy of the License at 
    7.  * 
    8.  * http://www.apache.org/licenses/LICENSE-2.0 
    9.  * 
    10.  * Unless required by applicable law or agreed to in writing, software 
    11.  * distributed under the License is distributed on an "AS IS" BASIS, 
    12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    13.  * See the License for the specific language governing permissions and 
    14.  * limitations under the License. 
    15.  */  
    16.   
    17. package net.itaem.aspect;  
    18.   
    19. import net.itaem.annotation.FileLog;  
    20.   
    21. import org.aspectj.lang.JoinPoint;  
    22. import org.aspectj.lang.annotation.AfterReturning;  
    23. import org.aspectj.lang.annotation.AfterThrowing;  
    24. import org.aspectj.lang.annotation.Aspect;  
    25. import org.springframework.stereotype.Component;  
    26.   
    27.   
    28. /** 
    29.  * 说明: 
    30.  * 日志的切面处理程序 
    31.  *  
    32.  * @author Fighter168 
    33.  */  
    34. @Aspect  
    35. @Component  
    36. public class LogAspect {  
    37.   
    38.     @AfterReturning("within(net.itaem..*) && @annotation(fl)")    
    39.     public void addSuccessLog(JoinPoint jp, FileLog fl){    
    40.         Object[] parames = jp.getArgs();  
    41.         //获取目标方法体参数    
    42.         String className = jp.getTarget().getClass().toString();  
    43.         //获取目标类名    
    44.         String signature = jp.getSignature().toString();  
    45.         //获取目标方法签名    
    46.         String methodName = signature.substring(signature.lastIndexOf(".")+1, signature.indexOf("("));   
    47.         //获取注解值  
    48.         String desc=fl.value();  
    49.         //把调用的信息写到日常记录信息里面去...  
    50.     }    
    51.     
    52.     //标注该方法体为异常通知,当目标方法出现异常时,执行该方法体    
    53.     @AfterThrowing(pointcut="within(net.itaem..*) && @annotation(fl)", throwing="e")    
    54.     public void addExceptionLog(JoinPoint jp, FileLog fl, Exception e){    
    55.        //把错误信息写到错误日志文件里面去...  
    56.     }    
    57. }  


    编写测试用例

    配置spring启动xml,配置如下
    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    4.     xmlns:aop="http://www.springframework.org/schema/aop"    
    5.     xsi:schemaLocation="  
    6.         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
    7.         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd  ">  
    8.           
    9.     <aop:aspectj-autoproxy/>    
    10.     <bean name="purchaseService"   class="net.itaem.test.PurchaseService" />  
    11.     <bean class="net.itaem.aspect.LogAspect"/>      
    12. </beans>  
     
    编写service类
    [java] view plain copy
     
    1. /** 
    2.  *  
    3.  * @author Fighter168 
    4.  */  
    5. public class PurchaseService {  
    6.   
    7.     /** 
    8.      *  
    9.      */  
    10.     public void purchaseProduct(String productName,int price,String type) {  
    11.         System.out.println("购买商品。。。");  
    12.     }  
    13.       
    14. }  
     
    编写测试代码
    [java] view plain copy
     
    1. package net.itaem.test;  
    2.   
    3. import org.springframework.context.ApplicationContext;  
    4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
    5.   
    6. public class Test {  
    7.   
    8.     @org.junit.Test  
    9.     public void test() {  
    10.         ApplicationContext context=new ClassPathXmlApplicationContext("net/itaem/source/test.xml");  
    11.         PurchaseService service=(PurchaseService) context.getBean("purchaseService");  
    12.         service.purchaseProduct("电风扇", 98, "日用品");  
    13.     }  
    14.        
    15. }  

    结果展示



    总结

    个人觉得这个实现起来比较简答, 也比较容易理解,当然其他的更深入的扩展,还是要慢慢的去学习,探索,这里只是简单的做了一个实现注解的方式介绍。其实学习的这种状态挺快乐的,无形中有一种自己又升华了的感觉,好好加油吧~
  • 相关阅读:
    python实例26[查询修改文件的属性]
    [SCM]源码管理 VisualSVN Server+TortoiseSVN
    持续集成之“依赖管理”
    Spoon:在“云”上运行桌面应用程序
    数字签名的验证
    判断Linux/Unix为32位或64位
    持续集成理论和实践的新进展
    [SCM]源码管理 SVN Server
    [BuildRelease Management]Parabuild
    为VM增加磁盘空间
  • 原文地址:https://www.cnblogs.com/handsome1013/p/7124773.html
Copyright © 2020-2023  润新知