spring-aop学习笔记

一 基本概念

通知(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/>

切面类:

@Aspect
public 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();
    }
}

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

@Aspect
public 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值