AOP注解方式
使用Spring的AOP注解开发,所需要引入的JAR跟xml方式是一样的,4个基础jar包,2个日志jar包,4个aop jar包,和1个整合junit的jar包 如下:
引入jar包:
还需要引入配置文件,并且配置文件中需要添加AOP的约束,下面是完整的约束,其中有AOP,注解组件扫描,事务,bean等约束
applicationContext.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
引入约束以后,还需要在配置文件中配置AOP命名空间的声明,让Spring为注解的切面类自动创建代理,织入切面,需要在配置文件中加入:
<!--在配置文件中开启AOP命名空间的声明-->
<!--自动创建代理-->
<aop:aspectj-autoproxy/>
<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强。
当配为<aop:aspectj-autoproxy poxy-target-class=“true”/>时,表示使用CGLib动态代理技术织入增强。
不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。
然后创建一个目标类OrderDao,并且创建四个目标方法:
OrderDao:
public class OrderDao {
public void save() { System.out.println("保存方法"); }
public void update() {
System.out.println("修改方法");
}
public void find() {
System.out.println("查询方法");
}
public void del() {
System.out.println("删除方法");
}
}
然后就是创建一个切面类MyAspectAnno,在类上添加 @Aspect 注解,让Spring将这个类识别为切面类。
在增强方法上使用@Before 注解,标志该方法为前置增强(通知),并且通过 value 属性配置表达式指定相应的目标方法。
MyAspectAnno:
/*
* 注解方式的切面类
* */
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//@Aspect 注解会让spring自动将这个类识别为切面类
@Aspect
public class MyAspectAnno {
//使用@Before注解,标识这是一个前置增强,以value属性通过表达式指定目标方法
@Before(value = "execution(* SpringDemo.OrderDao.save(..))")
public void before() {
System.out.println("前置增强=========");
}
}
然后将目标类和切面类交给Spring管理,在配置文件中声明两个bean标签:
<!--配置目标类-->
<bean name="orderDao" class="SpringDemo.OrderDao"/>
<!--配置切面类-->
<bean id="myAspect" class="SpringDemo.MyAspectAnno"/>
最后创建一个Spring整合Junit的测试类
test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class test {
@Resource(name ="orderDao")
private OrderDao orderDao;
@Test
public void test() {
orderDao.save();
}
}
AOP的注解通知类型
在所有的通知类型中,都可以通过JoinPoint 类设定参数,然后获得切入点的信息。
- @Before:前置通知
//使用@Before注解,标识这是一个前置增强,以value属性通过表达式指定目标方法
//增强方法可以通过joinPoint参数获得切入点的信心
@Before(value = "execution(* SpringDemo.OrderDao.save(..))")
public void before(JoinPoint joinPoint) {
System.out.println("前置增强=========" + joinPoint.getclass());
}
- @AfterReturning
//后置增强可以通过returning 获得方法中的返回值,returning定义的名称要和增强方法中的参数名称一样
@AfterReturning(value="execution(* SpringDemo.OrderDao.del(..))",returning = "result")
public void afterReturn(Object result){
System.out.println("后置增强========" + result);
}
- @Around:环绕通知
//环绕通知,通过ProceedingJoinPoint中的proceed方法来执行目标方法
// 同时创建一个object对象接收可能存在的返回值
//在proceed方法前后书写逻辑即可达到环绕的效果,甚至可以阻止目标方法运行
@Around(value="execution(* SpringDemo.OrderDao.update(..))")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前置通知");
//通过proceed执行目标方法,通过object类型接受方法可能存在的返回值
Object obj = proceedingJoinPoint.proceed();
System.out.println("环绕后置通知");
return obj;
}
- @AfterThrowing :异常抛出通知
//异常抛出通知是当目标方法抛出异常的情况下才会增强,
// 可以通过throwing 属性指定一个名称,要和增强方法中定义的Throwable参数名称一致
//可以通过Throwable类输出异常信息
@AfterThrowing(value="execution(* SpringDemo.OrderDao.find(..))",throwing="ex")
public void throwing(Throwable ex){
System.out.println("异常抛出通知" + ex.getMessage());
}
- After:最终通知
//最终通知
//最终通知无论发生什么情况,总是会执行,类似于finally代码块中的内容
@After(value="execution(* SpringDemo.OrderDao.find(..))")
public void after(){
System.out.println("执行最终通知");
}
切入点的注解
@Pointcut:切入点注解
//增强类名.切入点名称(方法名)的格式引用切入点方法
@After(value="MyAspectAnno.Pointcut4()")
public void after(){
System.out.println("执行最终通知");
}
//切入点的注解@Pointcut,类似于在XML中配置切入点信息一样
//还需要定义一个空的方法,并无实际作用,只起到给切入点设定名称的作用,所以定义为私有类型
//在增强方法中通过 增强类名.切入点名称(方法)的格式引用
@Pointcut(value="execution(* SpringDemo.OrderDao.save(..))")
private void Pointcut1(){}
@Pointcut(value="execution(* SpringDemo.OrderDao.del(..))")
private void Pointcut2(){}
@Pointcut(value="execution(* SpringDemo.OrderDao.find(..))")
private void Pointcut3(){}
@Pointcut(value="execution(* SpringDemo.OrderDao.update(..))")
private void Pointcut4(){}