Spring AOP基本原理及AOP两种配置方式初体验

    xiaoxiao2021-03-25  144

    在spring中,除了IOC(控制反转)之外,还有一个重要特性就是面向切面编程。

    AOP=面向切面的编程=Aspect Oriented Programming

    实现基本原理关键词:动态代理拓展程序功能、申明式事务管理

    1.Spring AOP 的一些术语: (1)切面(Aspect)   要增加什么功能?例如事务管理,日志管理,权限管理,异常处理 (2)连接点(Joinpoint)   哪个类的哪个方法上增加功能 (3) 通知(Advice)     加在方法的什么位置?前面?后面?产生异常时?环绕(前后都添加)?? (4)切入点(Pointcut)   给连接点命名,便于在多处使用 (5)目标对象(Target Object)   被代理对象,自己的功能不够强大,要通过aop加强 (6)AOP代理   功能已经加强的那个对象 (7)织入(weaving)   把新功能和本身的功能组织在一起执行

    2.注解配置AOP的实现

    这里还是结合一个注册案例来解释AOP基本注解配置。

    功能描述:在点击注册之后,将用户名和密码存入数据库中。现在想通过AOP实现在这个add方法调用之前控制台输出“方法开始”,在方法调用结束后输出“方法结束”。这里不在DAO实现类中添加这个功能,而是注解配置AOP来实现

    (1)要想添加日志功能先把日志功能在类中写出来。新建一个包 net.xinqushi.aop ,新建一个Log类 类中写两个方法,表示方法调用之前输出日志,调用之后输出日志

    把这个类变成一个切面类,表示这个类是添加到别的地方作为一个切面  注解:@Aspect 这个类也要初始化为一个对象  注解:@Component(value="log")   这里要在配置文件中把这个包加入到初始化为对象时搜索到包中。

    <context:component-scan base-package="net.xinqushi.dao.impl,net.xinqushi.service.impl,net.xinqushi.aop"/>

    (2)现在考虑打印日志的功能应该加在哪个类的哪个方法上?是加在方法执行之前,还是之后?

    在之前,这里就在方法之前添加注解 @Before("execution(public void net.xinqushi.service.impl.save(net.xinqushi.model.User))") 这里注意@Before一定要选 org.aspectj.lang.annotation.Aspect包下的 在之后,这里就结束方法之前添加注解 @AfterRunning("execution(public void net.xinqushi.service.impl.save(net.xinqushi.model.User))")

    (3)修改spring的配置文件  在applicationContex.xml文件中添加配置 添加命名空间  xmlns:aop="http://www.springframework.org/schema/aop" 添加xsd xml格式约束文件: http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd 使配置文件支持aop注解 <aop:aspectj-autoproxy/>

    3.这里再介绍一下优化注解配置的通配符法

    (1)joinpoint语法:用一些通配符来定义在哪些类和方法上增加aop功能。   语法:   1).execution(public * *(..))     所有public方法      2).execution(* set*(..))     所有以set作为方法名开头的方法   3).exuection(* com.xzy.service.AccountService.*(..))    com.xzy.service.AccountService类中的所有方法   4).execution(* com.xyz.service.*.*(..))    com.xyz.service包中所有类的所有方法   5).execution(* com.xyz.service..*.*(..))    com.xyz.service包及子包下的所有类的所有方法 (2)pointcut:给joinpoint取个名字。  使程序更加整洁   @pointcut(value="execution( * com.xzy.*.*(..))")   public void businessService(){} (3)advice   @Before  @AfterReturning  @AfterThrowing  @After(finally)  @Around (4)JoinPoint jp  可以为打印日志的before方法和end方法传进去一个参数 这个参数就可以get到很多关于连接点的信息。这里可以试着获得方法签名 这里导入的也是import org.aspectj.lang.JoinPoint;

    Log.java

    package net.xinqushi.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect @Component(value="log") public class Log { @Pointcut(value="execution(* net.xinqushi.service.impl.*.*(..))") public void myPoint(){} @Before("myPoint()") //方法执行之前输出 public void mybefore(JoinPoint jp){ System.out.println(jp.getSignature() +"方法开始执行"); } @AfterReturning("myPoint()") //方法执行完后输出 public void myafter(JoinPoint jp){ System.out.println(jp.getSignature()+"方法执行结束"); } } 5.AOP xml配置方式

    (1)先把Log.java中的注解配置注释掉,这里保留@Component(value="log")。因为xml方式也是要将这个类初始化为一个对象,当然这里也可以采用xml方式去初始化这个类。(前边博客有讲)

    (2)在配置文件中添加aop标签的配置

    这里之前在注解配置中引入的命名空间和xsd约束文件都是要保留的

    <?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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <context:annotation-config></context:annotation-config> <context:component-scan base-package="net.xinqushi.dao.impl,net.xinqushi.service.impl,net.xinqushi.aop"/> <aop:config> <aop:aspect ref="log"> <aop:pointcut expression="execution(* net.xinqushi.service.impl.*.*(..))" id="mypt"/> <aop:before method="mybefore" pointcut-ref="mypt"/> <aop:after method="myafter" pointcut-ref="mypt"/> </aop:aspect> </aop:config> <!-- 注解配置AOP才会用到的 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>

    其中这段注解大概的意思就是先把log设置为一个切面,然后设置切入点,再根据Log类中的两个打印日志的方法设置其pointcut-ref属性 <aop:config> <aop:aspect ref="log"> <aop:pointcut expression="execution(* net.xinqushi.service.impl.*.*(..))" id="mypt"/> <aop:before method="mybefore" pointcut-ref="mypt"/> <aop:after method="myafter" pointcut-ref="mypt"/> </aop:aspect> </aop:config>
    转载请注明原文地址: https://ju.6miu.com/read-6509.html

    最新回复(0)