跟着刚哥学习Spring框架--AOP(五)

AOP

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

使用"横切"技术,AOP把软件系统分为两个部分:核心关注点横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

基于Spring的AOP简单实现

1、通过配置文件实现AOP

首先需要额外上网下载两个jar包:

  ① aspectjrt.jar
  ② aspectjweaver.jar

先定义一个接口IHelloWorld:

1 public interface IHelloWorld {
2     void printHelloWorld(String name);
3 }

定义一个实现类HelloWorld

1 public class HelloWorld implements IHelloWorld {
2
3     @Override
4     public void printHelloWorld(String name) {
5         System.out.println("Print HelloWorld :" + name);
6     }
7 }

实现了两个切面(一个日志切面和一个时间切面)

1 public class LogAspect {
2     public void beforeLog(JoinPoint joinPoint){
3         System.out.println("log before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
4     }
5     public void afterLog(JoinPoint joinPoint){
6         System.out.println("log after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
7     }
8 }
1 public class TimeAspect {
2     public void beforeTime(JoinPoint joinPoint){
3         System.out.println("time before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
4     }
5     public void afterTime(JoinPoint joinPoint){
6         System.out.println("time after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
7     }
8 }

定义一个配置文件

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:context="http://www.springframework.org/schema/context"
 5        xmlns:aop="http://www.springframework.org/schema/aop"
 6        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">
 7
 8     <!-- 核心业务Bean -->
 9     <bean id="helloworld" class="com.hzg.HelloWorld"></bean>
10
11     <!-- 切面Bean(日志切面) -->
12     <bean id="logAspect" class="com.hzg.LogAspect"></bean>
13
14     <!-- 切面Bean(时间切面) -->
15     <bean id="timeAspect" class="com.hzg.TimeAspect"></bean>
16
17     <!-- AOP配置 -->
18     <aop:config>
19         <!-- 配置切点 -->
20         <aop:pointcut id="pointcut" expression="execution(* com.hzg.IHelloWorld.*(..))"></aop:pointcut>
21         <!-- 配置切面(日志切面)切面的优先级需要通过order定义 -->
22         <aop:aspect id="log" ref="logAspect" order="1">
23             <!-- 配置通知(前置通知、后置通知、返回通知、异常通知、环绕通知) -->
24             <aop:before method="beforeLog" pointcut-ref="pointcut"></aop:before>
25             <aop:after method="afterLog" pointcut-ref="pointcut"></aop:after>
26         </aop:aspect>
27         <!-- 配置切面(时间切面)切面的优先级需要通过order定义 -->
28         <aop:aspect id="time" ref="timeAspect" order="2">
29             <!-- 配置通知(前置通知、后置通知、后置返回通知、异常通知、环绕通知) -->
30             <aop:before method="beforeTime" pointcut-ref="pointcut"></aop:before>
31             <aop:after method="afterTime" pointcut-ref="pointcut"></aop:after>
32         </aop:aspect>
33     </aop:config>
34
35 </beans>

定义Main主方法

1 public static void main(String[] args) {
2         //由于ApplicationContext没有close方法,所以要使用它下面接口ConfigurableApplicationContext
3         ApplicationContext ctx = new ClassPathXmlApplicationContext("configaop.xml");
4         IHelloWorld helloworld = (IHelloWorld) ctx.getBean("helloworld");
5         helloworld.printHelloWorld("gangge");
6     }

输出结果:

log before method printHelloWorld参数 :[gangge]
time before method printHelloWorld参数 :[gangge]
Print HelloWorld :gangge
time after method printHelloWorld参数 :[gangge]
log after method printHelloWorld参数 :[gangge]

2、通过注解实现AOP

实现配置文件方式同样的功能

先定义一个接口文件(没区别)

1 public interface IHelloWorld {
2     void printHelloWorld(String name);
3 }

定义实现类(区别:加了一个注解@Component)

1 @Component
2 public class HelloWorld implements IHelloWorld {
3
4     @Override
5     public void printHelloWorld(String name) {
6         System.out.println("Print HelloWorld :" + name);
7     }
8 }

定义两个切面(一个日志切面和一个时间切面 区别:增加了@Component、@Aspect和@Order注解)

 1 @Component
 2 @Aspect
 3 @Order(1)
 4 public class LogAspect {
 5     public void beforeLog(JoinPoint joinPoint){
 6         System.out.println("log before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
 7     }
 8     public void afterLog(JoinPoint joinPoint){
 9         System.out.println("log after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
10     }
11 }
 1 @Component
 2 @Aspect
 3 @Order(2)
 4 public class TimeAspect {
 5     @Before("execution(* com.hzg.HelloWorld.*(..))")
 6     public void beforeTime(JoinPoint joinPoint){
 7         System.out.println("time before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
 8     }
 9     @After("execution(* com.hzg.HelloWorld.*(..))")
10     public void afterTime(JoinPoint joinPoint){
11         System.out.println("time after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
12     }
13 }

定义配置文件(区别:Spring自动扫描包和aop自动代理)

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:context="http://www.springframework.org/schema/context"
 5        xmlns:aop="http://www.springframework.org/schema/aop"
 6        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">
 7
 8     <context:component-scan base-package="com.hzg"></context:component-scan>
 9     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
10
11 </beans>

定义Main主方法(无区别)

1 public static void main(String[] args) {
2         //由于ApplicationContext没有close方法,所以要使用它下面接口ConfigurableApplicationContext
3         ApplicationContext ctx = new ClassPathXmlApplicationContext("configaop.xml");
4         IHelloWorld helloworld = (IHelloWorld) ctx.getBean("helloworld");
5         helloworld.printHelloWorld("gangge");
6     }

输出结果和配置文件一样

五种通知

1、前置通知

  上面已经有了,不再说明

2、后置通知

  上面已经有了,不再说明

3、返回通知

 1 /**
 2      * 返回通知: 方法正常执行完后调用,如果有异常,则不调用
 3      *          可以访问到方法的返回值
 4      * @param joinPoint
 5      * @param result   方法的返回值
 6      */
 7     @AfterReturning(value="execution(* com.hzg.*(..))",returning="result")
 8     public void afterReturning(JoinPoint joinPoint,Object result){
 9         //方法名
10         String methodName = joinPoint.getSignature().getName();
11         System.out.println("method "+methodName+" end:"+result);
12     }

4、异常通知

 1 /**
 2      * 异常通知: 当方法出现异常时
 3      *          可以指定出现哪些异常时才执行: 如何指定?通过入参指定,如:
 4      *          如果入参为NullPointException ex,那么只有在发生空指针异常时才执行
 5      * @param joinPoint
 6      * @param ex
 7      */
 8     @AfterThrowing(value="execution(* com.hzg.*(..))",throwing="ex")
 9     public void afterThrowing(JoinPoint joinPoint,Exception ex){
10         //方法名
11         String methodName = joinPoint.getSignature().getName();
12         System.out.println("method "+methodName+" occurs:"+ex);
13     }

5、环绕通知

  环绕通知类似于动态代理的全过程,可以使用环绕通知实现前置通知,后置通知,返回通知,异常通知的功能,十分强大,但并不常用

 1 /**
 2      * 环绕通知需要携带ProceedingJoinPoint类型的参数
 3      * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint这个类型的参数可以决定是否执行目标方法
 4      * 且环绕通知必须有返回值,返回值即为目标方法的返回值
 5      * @param pjd
 6      */
 7     @Around("execution(* com.hzg.*(..))")
 8     public Object around(ProceedingJoinPoint pjd){
 9         Object result = null;
10         String methodName = pjd.getSignature().getName();
11
12         try {
13             //前置通知
14             System.out.println("method:"+methodName+" begins with "+Arrays.asList(pjd.getArgs()));
15             //执行目标方法
16             result = pjd.proceed();
17             //返回通知
18             System.out.println("method:"+methodName+" end with "+result);
19         } catch (Throwable e) {
20             // 异常通知
21             System.out.println("method:"+methodName+" occurs exception "+e);
22         }
23         //后置通知
24         System.out.println("method ends");
25         return result;
26     }

-------------------------------------------------------------------------------------------------------------------------

跟着刚哥学习Spring框架系列:

跟着刚哥学习Spring框架--创建HelloWorld项目(一)

跟着刚哥学习Spring框架--Spring容器(二)

跟着刚哥学习Spring框架--通过XML方式配置Bean(三)

跟着刚哥学习Spring框架--通过注解方式配置Bean(四)

跟着刚哥学习Spring框架--AOP(五)

时间: 2024-10-05 21:06:32

跟着刚哥学习Spring框架--AOP(五)的相关文章

跟着刚哥学习Spring框架--通过XML方式配置Bean(三)

Spring配置Bean有两种形式(XML和注解) 今天我们学习通过XML方式配置Bean 1. Bean的配置方式 通过全类名(反射)的方式   √ id:标识容器中的bean.id唯一. √ class:bean的全类名,通过反射的方式在IOC容器中创建Bean,所以要求Bean中必须有无参的构造器 2.依赖注入的方式 1)属性注入:通过setter方法注入Bean的属性值或依赖的对象 属性注入使用<Property>元素,使用name指定Bean的属性名称,使用value指定Bean的属

跟着刚哥学习Spring框架--Spring容器(二)

Spring容器 启动Spring容器(实例化容器) -- IOC容器读取Bean配置创建Bean实例之前,必须对它进行实例化(加载启动),这样才可以从容器中获取Bean的实例并使用.  Bean是Spring管理的基本单位,任何的Java对象和组件都被当成Bean处理,容器还负责管理Bean与Bean之间的依赖关系.  两种类型的启动实现   1.BeanFactory:IOC容器的基本实现,是Spring框架的基础设施,面向Spring本身: -- Spring容器最基本的接口就是BeanF

跟着刚哥学习Spring框架--创建HelloWorld项目(一)

1.Spring框架简介 Spring是一个开源框架,Spring是在2003年兴起的一个轻量级的开源框架,由Rod johnson创建.主要对JavaBean的生命周期进行管理的轻量级框架,Spring给JavaEE带来了春天. 2.Spring框架特点 √ 轻量级:不是说他的文件大小很小,指的Spring是非侵入性. 知识点:轻量级框架和重量级框架的区别 轻量级和重量级的框架是以启动程序所需要的资源所决定,比如EJB在启动程序的时候需要消耗大量的资源,内存和CPU,所以是重量级.√ 依赖注入

跟着刚哥学习Spring框架--通过注解方式配置Bean(四)

组件扫描:Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件. 特定组件包括: 1.@Component:基本注解,识别一个受Spring管理的组件 2.@Respository:标识持久层组件 3.@Service:标识业务层组件 4.@Controller:标识表现层组件 Spring 有默认的命名策略: 使用非限定类名, 第一个字母小写. 也可以在注解中通过 value 属性值标识组件的名称 当在组件类上使用了特定的注解之后, 还需要在 Spring 的配置文件

跟着刚哥学习Spring框架--JDBC(六)

Spring的JDBC框架 Spring JDBC提供了一套JDBC抽象框架,用于简化JDBC开发. Spring主要提供JDBC模板方式.关系数据库对象化方式.SimpleJdbc方式.事务管理来简化JDBC编程 Spring提供了3个模板类: JdbcTemplate:Spring里最基本的JDBC模板,利用JDBC和简单的索引参数查询提供对数据库的简单访问. NamedParameterJdbcTemplate:能够在执行查询时把值绑定到SQL里的命名参数,而不是使用索引参数. Simpl

spring框架 AOP核心详解

AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知 (2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用 (3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

Spring框架AOP的使用及个人对底层原理的理解

Spring框架AOP的使用及个人对底层原理的理解**** 前言: AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础.它是一种面向切面编程的思想.关于AOP的基础知识,相信多数童鞋都已经了如指掌,今天要给大家分享的是Spring框架AOP的使用,以及我个人对底层原理的一些理解. Aop使用步骤 配置aop信息 <aop:config> 相当于aop的根节点 配置切入点 <aop:piontcut> 切入点 可以理解为需要增强的方法

马哥学习笔记二十五——ISCSI协议,架构及其安装配置

ISCSI监听在tcp/3260端口 iSCSI Target:iscsi-target-utils 客户端认正方式: 1.基于IP 2.基于用户,CHAP tgtadm:命令行工具,模式化命令 --mode 常用模式:target,logicalunit,account target --op new.delete.show.update.bind.unbind logicalunit --op new.delete account --op new.delete.bind.unbind --

Spring框架AOP源码剖析

今天我要和大家分享的是 AOP(Aspect-Oriented Programming)这个东西的源码剖析,作为多年的开发者,想必大家在面试的时候都被问过,你知道Spring框架AOP的底层实现机制吗,这可是很简单的噢,我们会说,如果某个类有接口就使用JDK动态代理,没有接口就用CGLIB动态代理,并且Spring也提供了可配置开关,不管有无接口都一律使用CGLIB动态代理,例如 <aop:aspectj-autoproxy proxy-target-class="true"/&