spring笔记--使用springAPI以及自定义类 实现AOP的一个例子

小编 2026-07-14 阅读:872 评论:0
  Spring的另一个重要思想是AOP,面向切面的编程,它提供了一种机制,可以在执行业务前后执...

  Spring的另一个重要思想是AOP,面向切面的编程,它提供了一种机制,可以在执行业务前后执行另外的代码,Servlet中的Filter就是一种AOP思想的体现,下面通过一个例子来感受一下.

  假设我们现在需要在针对数据库进行CRUD操作时添加一组日志,即在执行CRUD方法前后分别加上一句话,实现简单的面向切面编程的功能.我用到的是spring4,在配置文件上较之之前的版本可能有些不同.

  使用springAPI来实现AOP,除了spring必不可少的核心jar包,还需要两个jar包需要导入:

    1.   aspectjweaver.jar   下载链接: http://download.csdn.net/detail/luojiming1990/5432831
    2.   aopalliance.jar    下载链接:http://download.csdn.net/detail/zhaoshe/3153090

  并且配置文件的头文件也需要略作修改,需要加入aop的命名空间(namespace),详见下面实例中的beans.xml.

  UserService类(省略数据库操作代码,只做简单的打印来模拟):

public class UserService {    public void add(){        System.out.println("添加用户");    }    public void delete(){        System.out.println("删除用户");    }    public void update(){        System.out.println("修改用户");    }    public void search(){        System.out.println("查询用户");    }}

Log类(在执行增删改查方法前执行):

public class Log  implements MethodBeforeAdvice{    /***     * method:被调用的方法对象     * arg1:被调用的方法的参数     * target:被调用方法的目标对象      */    @Override    public void before(Method method, Object[] arg1, Object target)            throws Throwable {        System.out.println(target.getClass().getName()+"中的"+method.getName()+"方法被执行");    }}

AfterLog类(在执行增删改查方法后执行):

public class AfterLog implements AfterReturningAdvice{    /**     * returnValue:返回值类型     * method:被调用的方法对象     * arg1:被调用的方法的参数     * target:被调用方法的目标对象      */    @Override    public void afterReturning(Object returnValue, Method method,            Object[] args, Object target) throws Throwable {                System.out.println(target.getClass().getName()+"中的"+method.getName()+"方法被执行成功,返回值是"+returnValue);         }

spring配置文件(beans.xml):

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">    <bean id="userService" class="com.wang.service.UserService"></bean>    <bean id="log" class="com.wang.log.Log"></bean>    <bean id="afterlog" class="com.wang.log.AfterLog"></bean>    <aop:config>    <!--"*"为通配符表示所有方法,第一个* 表示任意返回值 第二个*表示所有方法              ".."表示任意个数的参数 -->        <aop:pointcut expression="execution(* com.wang.service.UserService.*())" id="pointcut"/>           <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>           <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>    </aop:config></beans>

测试代码testDemo:

   @Test    public void test1(){        ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");        UserService userService=(UserService)context.getBean("userService");        userService.add();        userService.search();    }

运行测试可以看到控制台的打印结果:

com.wang.service.UserService中的add方法被执行
添加用户
com.wang.service.UserService中的add方法被执行成功,返回值是null

com.wang.service.UserService中的search方法被执行
查询用户
com.wang.service.UserService中的search方法被执行成功,返回值是null

在配置文件中,我们看到了一些这样的代码:

 <aop:config>    <!--"*"为通配符表示所有方法              ".."表示任意个数的参数 -->        <aop:pointcut expression="execution(* com.wang.service.UserService.*())" id="pointcut"/>           <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>           <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>    </aop:config>

我们来介绍几个AOP的相关概念,这个就比较好理解了:

  • 切面(Aspect):在本例中.add(),delete(),等方法中都有一些代码,在真实的程序中这里不会只是简单的打印语句而是一些有意义的代码,这些代码可以看做是AOP的切面.
  • 通知(Advisor):本例中的两个日志类,这里可以成为拦截器,都是实现了某个*Advisor接口,这两个类就是指AOP中的通知,一旦Spring符合了条件,就会发出通知,与生活中我们所说的通知不同的是,Spring中的通知是带有执行代码的,能实现某种功能.
  • 切入点(pointcut):在配置拦截器(<aop-config>)的时候,xml中配置了UserService中所有的方法都是用拦截器,这个配置是通过spring中的一个已经写好的类完成的,这个类能配置对哪些方法使用拦截器,从那个地方"切入"进去.配置是可以使用通配符.

简而言之:"切入点"负责往"什么地方"插入代码,"通知"负责插入"什么代码".

 

  SpringAOP将公共的业务(如日志,安全)和领域业务结合,当执行领域业务时候把公共业务加进来,实现公共业务的重复利用,使得领域业务功能更加纯粹,程序员可以专注于领域业务.

  当然除了使用springAPI,我们也可以通过自定义的类,即不需要实现任何借口或继承任何类,的方式来实现上述功能:

  只需要一个Log类:

public class Log  {    public void before(){        System.out.println("执行方法前");    }        public void after(){        System.out.println("执行方法后");    }}

修改配置文件beans.xml中的<aop-config>为:

    <aop:config>           <aop:aspect ref="log">           <aop:pointcut expression="execution(* com.wang.service.UserService.*(..))" id="pointcut"/>               <aop:before method="before" pointcut-ref="pointcut"/>               <aop:after method="after" pointcut-ref="pointcut"/>           </aop:aspect>       </aop:config>

执行上面的测试代码,打印出的结果是:

执行方法前
添加用户
执行方法后
执行方法前
查询用户
执行方法后

 其实这种配置方式还可以用注解来完成,下面介绍一下使用注解的方式,顺带讲一个环绕方法,它和before和after一样,不过是在某一个方法前后都会执行的代码:

  Log类:

@Aspectpublic class Log  {    @Before("execution(* com.wang.service.*.*(..))")    public void before(){        System.out.println("执行方法前");    }    @After("execution(* com.wang.service.*.*(..))")    public void after(){        System.out.println("执行方法后");    }        @Around("execution(* com.wang.service.*.*(..))")    public Object around(ProceedingJoinPoint pjp) throws Throwable{        System.out.println("环绕前");        System.out.println("签名:"+pjp.getSignature());        //执行目标方法        Object proceed = pjp.proceed();        System.out.println("环绕后");        return proceed;    }

在beans.xml中,只需要将<aop-config>修改为一行代码:

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:aop="http://www.springframework.org/schema/aop"    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop.xsd">    <bean id="userService" class="com.wang.service.UserService"></bean>    <bean id="log" class="com.wang.log.Log"></bean>    <aop:aspectj-autoproxy/></beans>

打印结果如下,读者自行理解,这里对于around不再解释:

环绕前
签名:void com.wang.service.UserService.add()
执行方法前
添加用户
环绕后
执行方法后

如果希望在before和after方法中得到当前执行方法的方法名或者参数的话,可以在bofore或者after方法中加一个参数,就是上面around方法中的参数,

  获得方法名:String methodName=pjp.getSignature().getName();

  获得方法参数列表:List<Object> list=Arrays.toList(pjp.getArgs());

Spring支持5种类型的通知注解:

  @Before:前置通知,在方法执行前执行

  @After:后置通知,在方法执行后执行(此注解标注的方法无法得到方法的返回值)

  @AfterRunning:返回通知,在方法返回结果之后执行(此注解标注的方法,可以获取到方法的返回值)

  @AfterThrowing:异常通知,在方法抛出异常后执行

  @Around:环绕通知,问绕着方法执行(环绕通知必须要有ProceedingJoinPoint类型的参数,且必须要有返回值,见上面).

 

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
标签列表