spring学习笔记 -- day08 基于XML的Spring中的AOP
2017-08-16 11:32
190 查看
一、搭建AOP环境
1、创建项目,导入jar包
2、导入spring核心配置文件约束
<?xml version="1.0" encoding="UTF-8"?> <!-- 导入约束: 导入beans和aop两个约束 --> <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"> </beans>
3、创建业务层接口、实现类
package cn.itcast.service; /** * 客户的业务层接口 * @author wingzhe * */ public interface ICustomerService { /** * 保存客户 */ void saveCustomer(); /** * 更新客户 * @param i */ void updateCustomer(int i); /** * 删除客户 * @return */ int deleteCustomer(); }
package cn.itcast.service.impl; import cn.itcast.service.ICustomerService; import cn.itcast.utils.Logger; /** * 客户的业务层实现类 * @author wingzhe * */ public class CustomerServiceImpl implements ICustomerService { @Override public void saveCustomer() { System.out.println("执行了保存客户"); } @Override public void updateCustomer(int i) { System.out.println("执行了更新客户"); } @Override public int deleteCustomer() { System.out.println("执行了删除客户"); return 0; } }
4、编写要使用aop切入的动作(此处以记录日志类为例)
package cn.itcast.utils; /** * 记录日志的工具类 * 提供一个记录日志的方法 * @author winghze * */ public class Logger { /** * 计划让此方法在我们的业务方法执行之前执行 * 此方法是前置通知 */ public void printLog(){ System.out.println("Logger类中的printLog方法开始记录日志了"); } }
二、使用XML方式进行配置
1、配置spring主配置文件
<?xml version="1.0" encoding="UTF-8"?> <!-- 导入约束: 导入beans和aop两个约束 --> <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"> <!-- 把资源交给spring来管理 --> <bean id="customerService" class="cn.itcast.service.impl.CustomerServiceImpl"></bean> <!-- 配置spring基于xml的aop: 第一步:把通知类也交给spring来管理 --> <bean id="logger" class="cn.itcast.utils.Logger"></bean> <!-- 第二步:使用aop:config表示开始配置aop --> <aop:config> <!--第三步:使用aop:aspect开始配置切面 id属性:给切面提供一个唯一标识 ref属性:引用通知类bean的id --> <aop:aspect id="logAdvice" ref="logger"> <!-- 第四步:配置通知的类型 使用aop:before来配置前置通知 method:指定前置通知的方法名称 pointcut:指定切入点表达式。 关键字:execution(表达式) 表达式写法: 访问修饰符 返回值 包名....类名.方法名(参数列表) 全匹配方式: public void cn.itcast.service.impl.CustomerServiceImpl.saveCustomer() 访问修饰符可以省略 void cn.itcast.service.impl.CustomerServiceImpl.saveCustomer() 返回值可以使用*,表示任意返回值 * cn.itcast.service.impl.CustomerServiceImpl.saveCustomer() 包名可以使用*号,表示任意包。但是有几个包,就得写几个*号 * *.*.*.*.CustomerServiceImpl.saveCustomer() 包名可以使用..表达式当前包极其子包 * cn..CustomerServiceImpl.saveCustomer() 类名可以使用*,表示任意类 * cn..*.saveCustomer() 方法名可以使用*,表示任意方法 * cn..*.*() 参数列表可以使用*号,表示任意数据类型,但是有几个*就表示有几个参数 * cn..*.*(*) 参数列表可以使用..,表示有无参数均可 * cn..*.*(..) 全通配方式: * *..*.*(..) --> <aop:before method="printLog" pointcut="execution(* cn..*.*(..))"/> </aop:aspect> </aop:config> </beans>
2、编写测试类
package cn.itcast.ui; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.itcast.service.ICustomerService; public class Client { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); ICustomerService customerService = (ICustomerService)ac.getBean("customerService"); customerService.saveCustomer(); customerService.updateCustomer(1); customerService.deleteCustomer(); } }
三、切入点表达式
1、切入点表达式详解
关键字:execution(表达式)表达式写法:
访问修饰符 返回值 包名....类名.方法名(参数列表)
全匹配方式:
public void cn.itcast.service.impl.CustomerServiceImpl.saveCustomer()
访问修饰符可以省略
void cn.itcast.service.impl.CustomerServiceImpl.saveCustomer()
返回值可以使用*,表示任意返回值
* cn.itcast.service.impl.CustomerServiceImpl.saveCustomer()
包名可以使用*号,表示任意包。但是有几个包,就得写几个*号
* *.*.*.*.CustomerServiceImpl.saveCustomer()
包名可以使用..表达式当前包极其子包
* cn..CustomerServiceImpl.saveCustomer()
类名可以使用*,表示任意类
* cn..*.saveCustomer()
方法名可以使用*,表示任意方法
* cn..*.*()
参数列表可以使用*号,表示任意数据类型,但是有几个*就表示有几个参数
* cn..*.*(*)
参数列表可以使用..,表示有无参数均可
* cn..*.*(..)
全通配方式:
* *..*.*(..)
四、通知类型详解
1、通知类型配置方法
aop:before 用于配置前置通知。永远在切入点方法执行之前执行aop:after-returning 用于配置后置通知。在切入点方法正常执行之后执行。
aop:after-throwing 用于配置异常通知。在切入点方法执行产生异常后执行。
aop:after 用于配置最终通知。无论切入点方法是否正常执行,它都会在其后面执行。
2、修改记录日记的方法
package cn.itcast.utils; import org.aspectj.lang.ProceedingJoinPoint; /** * 记录日志的工具类 * @author zhy * */ public class Logger { /** * 前置通知 */ public void beforePrintLog(){ System.out.println("Logger类中的beforePrintLog方法开始记录日志了"); } /** * 后置通知 */ public void afterReturningPrintLog(){ System.out.println("Logger类中的afterReturningPrintLog方法开始记录日志了"); } /** * 异常通知 */ public void afterThrowingPrintLog(){ System.out.println("Logger类中的afterThrowingPrintLog方法开始记录日志了"); } /** * 最终通知 */ public void afterPrintLog(){ System.out.println("Logger类中的afterPrintLog方法开始记录日志了"); } /** * 环绕通知 * 问题: * 当我们配置了环绕通知,发现运行时,通知里面的代码执行了。而业务核心方法的代码没有执行。 * 分析: * 通过动态代理,我们得知环绕通知是指的整个invoke方法,里面明确的调用业务核心方法。 * 在我们配置的环绕通知中,没有明确的调用业务核心方法。 * 所以,才会只有环绕通知的代码执行,而service中的方法没有执行 * 解决: * spring框架给我们提供了一个接口,ProceedingJoinPoint,该接口可以作为环绕通知方法的参数。 * 在程序运行期间,spring框架会为我们提供该接口的实现类。 * 该接口中有一个方法:proceed();此方法就相当于明确的调用了业务核心方法 * * 环绕通知: * 它不是用于指定增强代码何时执行的,而是spring框架为我们提供的一种在代码中手动控制增强方法何时执行的方式。 */ public void aroundPringLog(ProceedingJoinPoint pjp){ try { System.out.println("前:Logger类中的aroundPringLog方法开始记录日志了"); pjp.proceed();//相当于调用service的方法(执行了业务层的核心方法) System.out.println("后:Logger类中的aroundPringLog方法开始记录日志了"); } catch (Throwable e) { System.out.println("异:Logger类中的aroundPringLog方法开始记录日志了"); e.printStackTrace(); }finally{ System.out.println("终:Logger类中的aroundPringLog方法开始记录日志了"); } } }
2、修改配置文件
注意:以下配置文件中不包含环绕通知,环绕通知需要另行配置<?xml version="1.0" encoding="UTF-8"?>
<!-- 导入约束:
导入beans和aop两个约束
-->
<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 daed
/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 把资源交给spring来管理 -->
<bean id="customerService" class="cn.itcast.service.impl.CustomerServiceImpl"></bean>
<bean id="logger" class="cn.itcast.utils.Logger"></bean>
<aop:config>
<!--所有的aop:aspect都可以使用 -->
<aop:pointcut expression="execution(void cn.itcast.service.impl.CustomerServiceImpl.saveCustomer())" id="pt1"/>
<aop:aspect id="logAdvice" ref="logger">
<!--配置通知的类型
aop:before 用于配置前置通知。永远在切入点方法执行之前执行
aop:after-returning 用于配置后置通知。在切入点方法正常执行之后执行。
aop:after-throwing 用于配置异常通知。在切入点方法执行产生异常后执行。
aop:after 用于配置最终通知。无论切入点方法是否正常执行,它都会在其后面执行。
-->
<aop:before method="beforePrintLog" pointcut-ref="pt1"/>
<aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"/>
<aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"/>
<aop:after method="afterPrintLog" pointcut-ref="pt1"/>
<!-- 配置切入点表达式 :只能在当前的aop:apsect中使用,如果是另外的一个aop:aspect不能用
<aop:pointcut expression="execution(void cn.itcast.service.impl.CustomerServiceImpl.saveCustomer())" id="pt1"/>
-->
</aop:aspect>
</aop:config>
</beans>
3、配置环绕通知
/*** 环绕通知
* 问题:
* 当我们配置了环绕通知,发现运行时,通知里面的代码执行了。而业务核心方法的代码没有执行。
* 分析:
* 通过动态代理,我们得知环绕通知是指的整个invoke方法,里面明确的调用业务核心方法。
* 在我们配置的环绕通知中,没有明确的调用业务核心方法。
* 所以,才会只有环绕通知的代码执行,而service中的方法没有执行
* 解决:
* spring框架给我们提供了一个接口,ProceedingJoinPoint,该接口可以作为环绕通知方法的参数。
* 在程序运行期间,spring框架会为我们提供该接口的实现类。
* 该接口中有一个方法:proceed();此方法就相当于明确的调用了业务核心方法
*
* 环绕通知:
* 它不是用于指定增强代码何时执行的,而是spring框架为我们提供的一种在代码中手动控制增强方法何时执行的方式。
*/
public void aroundPringLog(ProceedingJoinPoint pjp){
try {
System.out.println("前:Logger类中的aroundPringLog方法开始记录日志了");
pjp.proceed();//相当于调用service的方法(执行了业务层的核心方法)
System.out.println("后:Logger类中的aroundPringLog方法开始记录日志了");
} catch (Throwable e) {
System.out.println("异:Logger类中的aroundPringLog方法开始记录日志了");
e.printStackTrace();
}finally{
System.out.println("终:Logger类中的aroundPringLog方法开始记录日志了");
}
}
<aop:config>
<!--所有的aop:aspect都可以使用 -->
<aop:pointcut expression="execution(void cn.itcast.service.impl.CustomerServiceImpl.saveCustomer())" id="pt1"/>
<aop:aspect id="logAdvice" ref="logger">
<!-- 配置环绕通知:详细注释请看Logger类 -->
<aop:around method="aroundPringLog" pointcut-ref="pt1"/>
</aop:aspect>
</aop:config>
相关文章推荐
- Spring4 学习笔记(3)-Spring 基于 XML 的方式配置 Bean
- Spring4学习笔记-AOP(基于配置文件的方式)
- Spring学习-22:Spring的AOP:基于AspectJ的XML配置方式开发
- Spring MVC 学习笔记(一) 基于spring2.5的纯xml配置
- Spring4学习笔记-AOP(基于注解的方式)
- Spring学习笔记之二----基于XML的Spring AOP配置
- Spring MVC 学习笔记(一) 基于spring2.5的纯xml配置
- Spring学习笔记之一----基于XML的Spring IOC配置
- spring学习笔记(22)----基于配置文件的方式来配置AOP
- [原创]java WEB学习笔记108:Spring学习---基于配置文件的形式实现AOP
- JavaWeb学习笔记-spring-17-AOP-基于schema配置切面
- spring 学习笔记 使用pojo+xml的方式开发aop
- 20.Spring学习笔记_基于配置文件的方式来配置 AOP(by尚硅谷_佟刚)
- Spring4笔记----用基于 XML 的AOP配
- spring学习笔记 -- day13 基于XML的引入式整合
- spring学习笔记 -- day12 ssh整合之基于XML的独立式整合
- Spring学习总结7(AOP-基于XML)
- Java 学习笔记06:Spring 基于注解(Annotation)的AOP
- spring框架的学习(四)——Spring的AOP的概述及AOP的操作(基于aspectj的xml方式)
- spring学习笔记(13)基于Schema配置AOP详解