Spring的AOP开发(AspectJ的xml方式)
Spring的AOP简介
AOP思想最早是由AOP联盟组织提出的,Spring是使用这种思想的最好框架
Spring的AOP有自己的实现方式(非常繁琐)。AspectJ是一个AOP框架,Spring引入AspectJ作为自身AOP的开发
Spring的两套AOP开发方式
Spring传统方式(弃用)
Spring基于AspectJ的AOP的开发(使用)
AOP中的相关术语
Spring的AOP入门(基于AspectJ的xml方式)
创建web项目,引入jar包
除了原来的核心包和日志包外还需要下面四个
创建配置文件
引入约束
<?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 definitions here -->
</beans>
编写目标类并完成配置
实现了接口的目标类
/** * 接口 * @author ysh * ProductDao.java * 2018年11月1日 下午2:14:44 */ public interface ProductDao { public void save(); public void delete(); public void update(); public void find(); }
/** * 实现类 * @author ysh * ProductDaoImp.java * 2018年11月1日 下午2:15:21 * */ public class ProductDaoImp implements ProductDao{ @Override public void save() { System.out.println("saving products ...."); } @Override public void delete() { System.out.println("deleting products ...."); } @Override public void update() { System.out.println("updating products ...."); } @Override public void find() { System.out.println("finding products ...."); } }
<bean id="productDao" class="/springAOP/src/com/bwf/train1/ProductDaoImp"></bean>
编写测试类
Spring整合Junit(之后的测试都是用的本类中的方法,不用改动)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Test1 {
/*@Test
public void train1() {
//通过工厂获取bean
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
ProductDao dao = (ProductDao) applicationContext.getBean("productDao");
dao.save();
dao.delete();
dao.update();
dao.find();
}
*/
/*每次都要调用工厂方法,很麻烦,Spring提供了一种与Junit整合的办法(有一个jar包,框架包中的test包),
可以通过在类上注解省去这一步骤*/
@Resource(name="productDao")
private ProductDao productDao;
@Test
public void train2() {
productDao.save();
productDao.delete();
productDao.update();
productDao.find();
}
}
接下来,对save方法进行加强
配置切面
编写一个切面类
public class AspectXML { public void checkPri() { System.out.println("checked the user authority..."); } }
将切面类交个spring管理
<!-- 将切面类交个Spring管理 --> <bean id="AspectXMl" class="com.bwf.train1.AspectXML"></bean>
配置切面
测试结果
Spring中通知的类型
AspectJ中根据执行的先后顺序,将通知分为以下几类
前置通知
在目标方法执行之前进行操作 配置文件中用 aop:before 标签
前置通知 获取切入点信息
//在切面类中的方法中设置一个JoinPoint对象,可以输出JoinPoint(切入点)信息 public class AspectXML { public void checkPri(Joinpoint joinPoint) { System.out.println("checked the user authority..."+joinPoint); } }
运行结果
后置通知
在目标方法执行之后进行操作 配置文件中用 aop:after-returning 标签
后置通知 可以获取返回值
给delete方法改为返回一个String值
对delete方法进行后置通知,要获取返回值,需要设置一个returning属性
测试结果
环绕通知
在目标方法执行之前和之后进行操作 (添加事务可以用环绕通知)配置文件中用 aop:around 标签
环绕通知 阻止目标方法的执行(通知不执行,目标方法就没办法执行)
给update方法进行性能的监控
/** * 环绕通知 性能监控 * 必须返回Object类型,设置一个 * @throws Throwable */ public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕前====="); //这里相当于执行目标方法,目标方法可能有返回值,所以要返回一个object类型值 Object proceed = joinPoint.proceed(); System.out.println("环绕后====="); return proceed; }
测试结果
异常抛出通知
在程序出现异常时进行操作(在事物管理的时候,提交事物时,出现异常,回滚)
对find方法进行异常抛出通知
/** * 异常抛出通知 */ public void afterThrow() { System.out.println("异常抛出了。。。。"); }
测试结果
异常抛出通知 可以获取异常信息,只需要在切面配置中设置一个throwing属性
在通知方法中做如下改动
测试结果
最终通知
不管代码是否有异常,总是会执行(相当于try...catch....finally中的finally中的内容)
对find进行最终通知操作
/** * 最终通知 不管异常抛不抛出,都会执行 */ public void after() { System.out.println("最终执行的操作"); }
测试结果
引介通知(不会用到)
Spring切入点表达式的写法
切入点表达式语法:
基于execution()的函数来完成的
语法 [ ]表示可选
[ 访问修饰符 ] 空格 方法的返回值 空格 包名.类名.方法名(参数)
例如 public void com.bwf.spring.CustomerDao.save(..)
* *.*.*Dao.save(..)表示返回值是任意类型,有两层包名,类名以Dao结束的有任意参数的save方法,即所有dao中的save方法都可以被增强
* com.bwf.spring.CustomerDao+.save(..) " + "表示CustomerDao类和其子类
* com.bwf.spring..*.*(..) 表示com.bwf.spring这个包及其子包下的所有类的所有方法
* *.*.*(..) 表示所有包下的所有类中的所有方法