spring-aop学习笔记

来源:互联网 发布:数据有效性输入空格 编辑:程序博客网 时间:2024/04/29 23:45

一 基本概念

通知(Advice):切面的工作被称为通知。定义了切面是什么以及何时使用。spring切面可以应用5种类型的通知(Before、After、After-retrunning,After-throwing, Around)。

连接点(JointPoint):是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。

切点(Pointcut):切点定义了切面在何处。切点的定义会匹配通知所要织入的一个或多个连接点,我们通常使用明确的类和方法名称指定这些切点,或者利用正则表达式定义匹配的类和方法名称模式来指定这些切点。


切面(Aspect): 是通知和切点的结合,通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能。


引入(introduction):允许我们向现有的类添加新方法或属性。


织入(Weaving): 将切面应用到目标对象来创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以织入。(编译器、类加载期、运行期)


二 基于xml配置的使用

目标类:

public interface IHelloWorldService {    public void sayHello();}
public class HelloWorldService implements IHelloWorldService {    @Override    public void sayHello() {        System.out.println("say hello");    }}

切面类:

public class HelloWorldAspect {    //前置通知    public void beforAdvice(){        System.out.println("====before=====");    }    //后置通过    public void afterFinallyAdvice(){        System.out.println("====after====");    }}


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-3.0.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">        <bean id = "helloWorldService" class="aopTest.HelloWorldService"/>    <bean id="aspect" class="aopTest.HelloWorldAspect"/>     <aop:config>        <aop:pointcut id="pointcut" expression="execution(* aopTest..*.*(..))"/>        <aop:aspect ref="aspect">            <aop:before pointcut-ref="pointcut" method="beforAdvice"/>            <aop:after pointcut-ref="pointcut" method="afterFinallyAdvice"/>        </aop:aspect>    </aop:config></beans>

<aop:config>用户配置aop

<aop:pointcut> 定义切点 

<aop:aspect> 定义切面,其中ref用来引用切面支持类的bean。

<aop:before>前置通知 pointcut-ref 切点,引用在前面定义的切点,也可以直接使用pointcut定义一个匿名切点。mehthod 引用切换通知实现类中的方法,即在目标类方法执行之前调用的方法。

<aop:after>后置通知


测试类:

public class AopTest {    @Test    public void test(){        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("aop/spring-aop.xml");        IHelloWorldService helloWorldService = applicationContext.getBean(IHelloWorldService.class);        helloWorldService.sayHello();    }}

输出结果:

====before=====

say hello

====after====


调试时,也可以看到helloWorldService类被spring代理了。


如果是有入参的方法,可以使用如下方式定义:

<?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-3.0.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">    <!--<aop:aspectj-autoproxy/>-->    <bean id = "helloWorldService" class="aopTest.HelloWorldService"/>    <bean id="aspect" class="aopTest.HelloWorldAspect"/>    <aop:config>        <aop:pointcut id="pointcut" expression="execution(* aopTest..*.*(..)) and args(param)"/>        <aop:aspect ref="aspect">            <aop:before pointcut-ref="pointcut" method="beforAdvice" arg-names="param"/>            <aop:after pointcut-ref="pointcut" method="afterFinallyAdvice" arg-names="param"/>        </aop:aspect>    </aop:config></beans>
其中需要注意的是

(1) pointCut中的expression中必须包含 args(param),否则会在运行时报错:0 formal unbound in pointcut 

args是在用于匹配当前执行的方法传入的参数为指定类型的执行方法,是在运行时切入的,属于动态切入。

(2) 如果pointCut中包含 args(param), 则before和after通知的方法也必须包含该参数。

(3) before和after通知中arg-names可以省略不写。

(4) 可以通过order字段配置通知的优先级。order字段值越大,优先级越高。

  <aop:config>        <aop:pointcut id="pointcut" expression="execution(* aopTest..*.*(..)) and args(param)"/>        <aop:aspect ref="aspect" order="2">            ......        </aop:aspect>    </aop:config>



三 基于注解的使用

Spring默认不支持@AspectJ风格的切面声明,为了支持需要使用如下配置:

<aop:aspectj-autoproxy/>

切面类:

@Aspectpublic class HelloWorldAspect2 {    @Pointcut(value = "execution(* aopTest..*.*(..))")    public void pointTest(){};    @Before(value = "pointTest()")    public void before(){        System.out.println("====before===");    }}

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-3.0.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">    <aop:aspectj-autoproxy/>    <bean id = "helloWorldService" class="aopTest.HelloWorldService"/>    <bean id = "aspect2" class="aopTest.HelloWorldAspect2"/></beans>


测试类:

public class AopTest {    @Test    public void test(){        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("aop/spring-aop.xml");        IHelloWorldService helloWorldService = applicationContext.getBean(IHelloWorldService.class);        helloWorldService.sayHello();    }}

如果是有入参的方法,可以使用如下方式定义:

@Aspectpublic class HelloWorldAspect2 {    @Pointcut(value = "execution(* aopTest..*.*(..)) && args(arg)")    public void pointTest(String arg){};    @Before(value = "pointTest(arg)")    public void before(String arg){        System.out.println("====before === + " + arg);    }}


可以通过order字段制定通知的优先级:

@Aspect@Order(1)public class HelloWorldAspect2 {   .....}



四 其他

aspectJ语法:http://www.importnew.com/17828.html

AspectJ类型匹配的通配符:

* : 匹配任何数量字符

.. : (两个点)匹配任何数量字符的重复。如在类型模式中匹配任何数量子包,而在方法参数模式中匹配任何数量参数

+:匹配执行类型的子类型,仅能作为后缀放在类型模式后边。


java.*.String: 匹配Java包下任何的一级子包的下的String类型,匹配java.lang.String,但不匹配java.lang.ss.String

java..* 匹配java包以及任何子包下的任何类型。匹配java.lang.String,java.lang.ss.String


采用JoinPoint传递参数:

使用方法非常简单,直接在通知方法中增加一个入参,需要注意的是,该入参需要放在第一个位置。

 public void beforAdvice(JoinPoint joinPoint,String param){        System.out.println("====beforeAdvice=====" + param);    }

其中JoinPoint有几个属性,getTarget()——获取目标对象

getThis()——获取代理对象,getArgs()——获取被通知对象的入参列表


Spring AOP通过代理模式实现,目前支持两种代理:JDK动态代理、CGLIB代理来创建AOP代理,Spring建议优先使用JDK动态代理.

要采用cglib代码:

对于xml配置的切面:

<aop:config proxy-target-class="true"> </aop:config>

对于基于@Aspect注解的切面:

<aop:aspectj-autoproxy proxy-target-class="true"/>





参考资料: http://www.importnew.com/17828.html

http://www.importnew.com/17813.html

http://www.importnew.com/17755.html

0 0