JAVA入门[14]-Spring MVC AOP
一、基本概念
1.AOP简介
DI能够让相互协作的软件组件保持松散耦合;而面向切面编程(aspect-oriented programming,AOP)允许你把遍布应用各处的功能分离出来形成可重用的组件。把这些横切关注点与业务逻辑相分离正是面向切面编程(AOP)所要解决的问题
常见场景:日志、安全、事物、缓存
2.AOP用到的一些术语
项目中每个模块的核心功能都是为特定业务领域提供服务,但是这些模块都需要类似的辅助功能,例如安全和事务管理,这时候需要引入AOP的概念。
通知定义了切面是什么以及何时使用, Spring切面可以应用5种类型的通知:
- 前置通知(Before):在目标方法被调用之前调用通知功能;
- 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
- 返回通知(After-returning):在目标方法成功执行之后调用通知;
- 异常通知(After-throwing):在目标方法抛出异常后调用通知;
- 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
连接点(join potint)是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为
切点(poincut)的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点
二、准备service模块
1.service bean
public class CategoryService1 {
public void add(int id) {
System.out.println("CategoryService1.add()");
}
} public class CategoryService2{
public void add(int id) {
System.out.println("CategoryService2.add()");
}
}
2.配置bean
<?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"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"> <bean id="categoryServiceImpl" class="service.CategoryService1"></bean>
<bean id="CategoryServiceImpl2" class="service.CategoryService2"></bean>
</beans>
3.单元测试
@Test
public void test(){
ApplicationContext context=new ClassPathXmlApplicationContext("aop.xml"); CategoryService1 service1=context.getBean(CategoryService1.class);
service1.add(1); CategoryService2 service2=context.getBean(CategoryService2.class);
service2.add(2);
}
运行结果:
CategoryService1.add()
CategoryService2.add()
三、XML方式声明AOP
Spring所创建的通知都是用标准的Java类编写的, 定义通知所应用的切点通常会使用注解或在Spring配置文件里采用XML来编写,这两种语法对于Java开发者来说都是相当熟悉的。
注意Spring只支持方法级别的连接点。
切入点表达式
execution指示器是我们在编写切点定义时最主要使用的指示器
Demo
我们要实现的一个简单示例是:在service方法调用前和调用后打印日志“write log”。
public class LogHandler {
public void log(){
System.out.println("write log.");
}
}
aop.xml添加配置:
<bean id="logHandler" class="pointcut.LogHandler"></bean>
<aop:config>
<aop:aspect id="log" ref="logHandler">
<aop:pointcut id="addLog" expression="execution(* service.*.*(..))"></aop:pointcut>
<aop:before method="log" pointcut-ref="addLog"></aop:before>
<aop:after method="log" pointcut-ref="addLog"></aop:after>
</aop:aspect>
</aop:config>
单元测试:
public class AopTests {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
CategoryService1 service1 = context.getBean(CategoryService1.class);
service1.add(1);
CategoryService2 service2 = context.getBean(CategoryService2.class);
service2.add(2);
}
}
运行报错:
org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException
原来是忘了pom依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
运行结果:
write log.
CategoryService1.add()
write log.
write log.
CategoryService2.add()
write log.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>DemoStore</groupId>
<artifactId>DemoAOP</artifactId>
<version>1.0-SNAPSHOT</version> <properties>
<spring.version>4.3.5.RELEASE</spring.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies> </project>
完整的pom.xml
四、aop:around
通过使用环绕通知,可以实现前置通知和后置通知所实现的功能,而且只需要在一个方法中实现。
public class LogTimeHandler {
public void log(ProceedingJoinPoint jp) throws Throwable {
try {
System.out.println("1.before log "+new Date().getTime());//记录开始时间
jp.proceed();
System.out.println("2.after log "+new Date().getTime());//记录结束时间
}catch (Exception e){
System.out.println("log fail ");
}
}
}
在aop1.xml中配置aop:round通知
<?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 id="categoryService" class="service.CategoryService1"></bean>
<bean id="logHanlder" class="pointcut.LogTimeHandler"></bean>
<aop:config>
<aop:aspect id="log" ref="logHanlder">
<aop:pointcut id="addlog" expression="execution(* service.*.*(..))"></aop:pointcut>
<aop:around method="log" pointcut-ref="addlog"></aop:around>
</aop:aspect>
</aop:config>
</beans>
单元测试:
public class AopTest1 {
@Test
public void test(){
ApplicationContext context=new ClassPathXmlApplicationContext("aop1.xml");
CategoryService1 service1=context.getBean(CategoryService1.class);
service1.add(1);
}
}
运行结果:
1.before log 1489990832246
CategoryService1.add()
2.after log 1489990832263
五、注解方式创建AOP
定义切面需要给类添加@Aspect注解。然后需要给方法添加注解来声明通知方法,各通知类型对应的注解:
- @After 通知方法会在目标方法返回或抛出异常后
- @AfterReturning 通知方法会在目标方法返回后调用
- @AfterThrowing 通知方法会在目标方法抛出异常后调用
- @Around 通知方法会将目标方法封装起来
- @Before 通知方法会在目标方法调用之前执行
@Component
@Aspect
public class LogHelper3 { @Before("execution(* service.*.*(..))")
public void logStart(){
System.out.println("log start "+new Date().getTime());
}
}
然后定义JavaConfig类,注意需要给类添加@EnableAspectJAutoProxy注解启用自动代理功能。
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackageClasses = {service.CategoryService3.class,pointcut.LogHelper3.class})
public class BeanConfig {
}
单元测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = BeanConfig.class)
public class AopTest3 { @Autowired
CategoryService3 service; @Test
public void testConfigAop(){
service.add(100);
}
}
运行结果:
log start 1489990977264
add category id=100
结尾:
参考:《spring实战》
源码下载:https://github.com/cathychen00/learnjava/tree/master/DemoAOP
JAVA入门[14]-Spring MVC AOP的更多相关文章
- java企业架构 spring mvc +mybatis + KafKa+Flume+Zookeeper
声明:该框架面向企业,是大型互联网分布式企业架构,后期会介绍linux上部署高可用集群项目. 项目基础功能截图(自提供了最小部分) 平台简介 Jeesz是一个分布式的框架,提供 ...
- JAVA入门[13]-Spring装配Bean
一.概要 Sping装配bean主要有三种装配机制: 在XML中进行显式配置. 在Java中进行显式配置. 隐式的bean发现机制和自动装配. 原则: 建议尽可能地使用自动配置的机制,显式配置越少越好 ...
- 第63节:Java中的Spring MVC简介笔记
前言 感谢! 承蒙关照~ Java中的Spring MVC简介笔记 MVC简介 Spring MVC 基本概念 Spring MVC 项目搭建 maven 使用Spring MVC进行开发 实现数据绑 ...
- Java方式配置Spring MVC
概述 使用Java方式配置Spring MVC,以及回顾一下Spring MVC的各种用法. Spring MVC简述 关于Spring MVC的介绍网上有很多,这里就不再赘述了,只是要说一下,Spr ...
- 【Java】关于Spring MVC框架的总结
SpringMVC是一种基于Java,实现了Web MVC设计模式,请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将Web层进行职责解耦.基于请求驱动指的就是使用请求-响应模型,框架的 ...
- 如何用Java类配置Spring MVC(不通过web.xml和XML方式)
DispatcherServlet是Spring MVC的核心,按照传统方式, 需要把它配置到web.xml中. 我个人比较不喜欢XML配置方式, XML看起来太累, 冗长繁琐. 还好借助于Servl ...
- [Java] Maven 建立 Spring MVC 工程
GIT: https://github.com/yangyxd/Maven.SpringMVC.Web 1. 建立 WebApp 工程 下一步: 下一步: 选择 maven-archetype-web ...
- Java框架之Spring MVC(二)
一.Spring MVC 验证 JSR 303 是ajvaEE6 中的一项子规范 ,叫 Bean Validation 用于对javaBean中的字段进行校验. 官方的参考实现是: Hibernate ...
- Java框架之Spring MVC(一)
一.Spring简介 Spring MVC是当前最优秀的 MVC 框架,自从Spring 2.5 版本发布后,由于支持注解配置,易用性有了大幅度的提高.Spring 3.0 更加完善,实现了对 Str ...
随机推荐
- mysql +keeplive
下载tar包 ./configure --prefix=/usr/local/keepalived --with-kernel-dir=/usr/src/kernels/2.6.32-431.el6. ...
- 【机器学习】TensorFlow学习(一)
感谢中国人民大学胡鹤老师,课讲得非常好~ 首先,何谓tensor?即高维向量,例如矩阵是二维,tensor是更广义意义上的n维向量(有type+shape) TensorFlow执行过程为定义图,其中 ...
- C#获取存储过程的 Return返回值和Output输出参数值
1.获取Return返回值 程序代码 //存储过程//Create PROCEDURE MYSQL// @a int,// @b int//AS// return @a + ...
- 异步 HttpContext.Current实现取值的方法(解决异步Application,Session,Cache...等失效的问题)
在一个项目中,为了系统执行效率更快,把一个经常用到的数据库表通过dataset放到Application中,发现在异步实现中每一次都会出现HttpContext.Current为null的异常,后来在 ...
- Bean property属性说明
来自为知笔记(Wiz)
- [转载] ETL和Kettle
http://tech.ccidnet.com/art/1105/20080407/1411567_1.html http://blog.csdn.net/cissyring/article/deta ...
- python基础-------函数(一)
一 为何要有函数?不加区分地将所有功能的代码垒到一起, 问题是: 代码可读性差 代码冗余 代码可扩展差 如何解决?函数即工具,事先准备工具的过程是定义函数,拿来就用指的就是函数调用 结论:函数使用必须 ...
- Zabbix 3.0 从入门到精通(zabbix使用详解)
第1章 zabbix监控 1.1 为什么要监控 在需要的时刻,提前提醒我们服务器出问题了 当出问题之后,可以找到问题的根源 网站/服务器 的可用性 1.1.1 网站可用性 在软件系统的高可靠性(也 ...
- 洛谷 P3391 【模板】文艺平衡树
题目背景 这是一道经典的Splay模板题--文艺平衡树. 题目描述 您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4 ...
- 提高运维效率(二)桌面显示IP
运维人员远控电脑询问IP时,总要告诉用户找ip的步骤,岂不很烦? 以下方法直观地把ip地址显示在桌面上,再做个入职培训,即可提高运维效率. 1. 下载bginfo.exe软件,放到域控下的netlo ...