JAVA入门[14]-Spring MVC AOP

简介:


一、基本概念

1.AOP简介

DI能够让相互协作的软件组件保持松散耦合;而面向切面编程(aspect-oriented programming,AOP)允许你把遍布应用各处的功能分离出来形成可重用的组件。把这些横切关注点与业务逻辑相分离正是面向切面编程(AOP)所要解决的问题

常见场景:日志、安全、事物、缓存

Image(2)

2.AOP用到的一些术语

项目中每个模块的核心功能都是为特定业务领域提供服务,但是这些模块都需要类似的辅助功能,例如安全和事务管理,这时候需要引入AOP的概念。

Image(3)

通知定义了切面是什么以及何时使用, Spring切面可以应用5种类型的通知:

  • 前置通知(Before):在目标方法被调用之前调用通知功能;
  • 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
  • 返回通知(After-returning):在目标方法成功执行之后调用通知;
  • 异常通知(After-throwing):在目标方法抛出异常后调用通知;
  • 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

连接点(join potint)是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为

切点(poincut)的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点

 

二、准备service模块

1.service bean

1
2
3
4
5
6
7
8
9
10
11
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

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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.单元测试

1
2
3
4
5
6
7
8
9
10
@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指示器是我们在编写切点定义时最主要使用的指示器

Image(4)

 

Demo

我们要实现的一个简单示例是:在service方法调用前和调用后打印日志“write log”。

1
2
3
4
5
public  class  LogHandler {
     public  void  log(){
         System.out.println( "write log." );
     }
}

aop.xml添加配置:

1
2
3
4
5
6
7
8
<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> 

单元测试:

1
2
3
4
5
6
7
8
9
10
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依赖:

1
2
3
4
5
<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.

  完整的pom.xml

 

四、aop:around

通过使用环绕通知,可以实现前置通知和后置通知所实现的功能,而且只需要在一个方法中实现。

1
2
3
4
5
6
7
8
9
10
11
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通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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>

  

单元测试:

1
2
3
4
5
6
7
8
public  class  AopTest1 {
     @Test
     public  void  test(){
         ApplicationContext context= new  ClassPathXmlApplicationContext( "aop1.xml" );
         CategoryService1 service1=context.getBean(CategoryService1. class );
         service1.add( 1 );
     }
}

运行结果:

1
2
3
1 .before log  1489990832246
CategoryService1.add()
2 .after log  1489990832263

  

五、注解方式创建AOP

定义切面需要给类添加@Aspect注解。然后需要给方法添加注解来声明通知方法,各通知类型对应的注解:

  • @After 通知方法会在目标方法返回或抛出异常后
  • @AfterReturning 通知方法会在目标方法返回后调用
  • @AfterThrowing 通知方法会在目标方法抛出异常后调用
  • @Around 通知方法会将目标方法封装起来
  • @Before 通知方法会在目标方法调用之前执行
1
2
3
4
5
6
7
8
9
@Component
@Aspect
public  class  LogHelper3 {
 
     @Before ( "execution(* service.*.*(..))" )
     public  void  logStart(){
         System.out.println( "log start " + new  Date().getTime());
     }
}

然后定义JavaConfig类,注意需要给类添加@EnableAspectJAutoProxy注解启用自动代理功能。

1
2
3
4
5
@Configuration
@EnableAspectJAutoProxy
@ComponentScan (basePackageClasses = {service.CategoryService3. class ,pointcut.LogHelper3. class })
public  class  BeanConfig {
}

  单元测试:

1
2
3
4
5
6
7
8
9
10
11
12
@RunWith (SpringJUnit4ClassRunner. class )
@ContextConfiguration (classes = BeanConfig. class )
public  class  AopTest3 {
 
     @Autowired
     CategoryService3 service;
 
     @Test
     public  void  testConfigAop(){
         service.add( 100 );
     }
}

运行结果:

1
2
log start  1489990977264
add category id= 100

  

结尾:

参考:《spring实战》

源码下载:https://github.com/cathychen00/learnjava/tree/master/DemoAOP




    本文转自 陈敬(Cathy) 博客园博客,原文链接:http://www.cnblogs.com/janes/p/6873732.html,如需转载请自行联系原作者



相关文章
|
2月前
|
前端开发 Java 数据库
SpringBoot入门 - 对Hello world进行MVC分层
SpringBoot入门 - 对Hello world进行MVC分层
53 3
SpringBoot入门 - 对Hello world进行MVC分层
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
103 2
|
8天前
|
Java Spring
Java Spring Boot监听事件和处理事件
通过上述步骤,我们可以在Java Spring Boot应用中实现事件的发布和监听。事件驱动模型可以帮助我们实现组件间的松耦合,提升系统的可维护性和可扩展性。无论是处理业务逻辑还是系统事件,Spring Boot的事件机制都提供了强大的支持和灵活性。希望本文能为您的开发工作提供实用的指导和帮助。
50 15
|
19天前
|
存储 安全 Java
Spring Security 入门
Spring Security 是 Spring 框架中的安全模块,提供强大的认证和授权功能,支持防止常见攻击(如 CSRF 和会话固定攻击)。它通过过滤器链拦截请求,核心概念包括认证、授权和自定义过滤器。配置方面,涉及密码加密、用户信息服务、认证提供者及过滤器链设置。示例代码展示了如何配置登录、注销、CSRF防护等。常见问题包括循环重定向、静态资源被拦截和登录失败未返回错误信息,解决方法需确保路径正确和添加错误提示逻辑。
Spring Security 入门
|
6天前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
|
7天前
|
人工智能 自然语言处理 Java
Spring Cloud Alibaba AI 入门与实践
本文将介绍 Spring Cloud Alibaba AI 的基本概念、主要特性和功能,并演示如何完成一个在线聊天和在线画图的 AI 应用。
123 7
|
1月前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
67 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
2月前
|
前端开发 Java 数据库
SpringBoot入门(3) - 对Hello world进行MVC分层
SpringBoot入门(3) - 对Hello world进行MVC分层
20 1
 SpringBoot入门(3) - 对Hello world进行MVC分层
|
1月前
|
Java 数据库连接 数据库
从入门到精通---深入剖析Spring DAO
在Java企业级开发中,Spring框架以其强大的功能和灵活性,成为众多开发者的首选。Spring DAO(Data Access Object)作为Spring框架中处理数据访问的重要模块,对JDBC进行了抽象封装,极大地简化了数据访问异常的处理,并能统一管理JDBC事务。本文将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring DAO,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
26 1
|
2月前
|
监控 Java 数据安全/隐私保护
如何用Spring Boot实现拦截器:从入门到实践
如何用Spring Boot实现拦截器:从入门到实践
58 5