《Spring之AOP、IOC》
2022-09-22 22:42:48

本篇总结了一些工作中常用的和关键的Spring知识。

[TOC]

0. Spring

sp01.png

模块概括如下

核心容器(Core Container)

  1. 核心容器由spring-corespring-beansspring-contextspring-context-support,和spring-expression(Spring Expression Language) 5个模块组成。
  2. spring-corespring-beans模块提供框架的基本零件,包括IOC和依赖注入特征。BeanFactory是一个复杂的工厂模式实施。它消除了对程序化单例的需求,并允许将实际程序逻辑中的依赖关系的配置和规范分离。
  3. Context (spring-context) 模块建立由设置在固体基体上的核心和豆类模块:它是访问一个框架式的方式是类似于一个JNDI注册表对象的装置。Context模块从Beans模块中继承了它的特性,并增加了对国际化(例如使用资源包),事件传播,资源加载以及例如Servlet容器的上下文透明创建的支持。Context模块还支持Java EE功能,如EJB,JMX和基本远程处理。该ApplicationContext接口是语境模块的焦点。 spring-context-support 提供了将常见的第三方库集成到Spring应用程序上下文中的支持,特别是用于缓存(EhCache,JCache)和调度(CommonJ,Quartz)。
  4. spring-expression模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是JSP 2.1规范中规定的统一表达式语言(统一EL)的扩展。该语言支持设置和获取属性值,属性赋值,方法调用,访问数组的内容,集合和索引器,逻辑和算术运算符,命名变量以及从Spring的IoC容器中按名称检索对象。它还支持列表预测和选择以及常用列表聚合。

AOP and Instrumentation(仪表)

  1. spring-aop模块提供了符合AOP联盟的面向方面编程实现,允许您定义方法拦截器和切入点,以干净地分离实现应该分离的功能的代码。使用源代码级元数据功能,您还可以将行为信息以类似于.NET属性的方式整合到您的代码中。
  2. spring-aspects模块提供与AspectJ的集成。
  3. spring-instrument模块提供了在特定应用程序服务器中使用的类工具支持和类加载器实现。
  4. spring-instrument-tomcat 模块包含Tomcat的Spring工具代理。

Messaging

Spring框架4包括spring-messaging从关键抽象模块 Spring集成项目,例如MessageMessageChannelMessageHandler,和其他人作为基于消息的应用奠定了基础。该模块还包括一组用于将消息映射到方法的注释,类似于基于Spring MVC注释的编程模型。

Data Access/Integration(数据访问/集成)

所述数据访问/集成层由JDBC,ORM,OXM,JMS和交易模块。

  1. spring-jdbc模块提供了一个JDBC -abstraction层消除了需要冗长的JDBC编码和数据库厂商特有的错误代码解析。
  2. spring-tx模块支持编程和声明式事务 管理,用于实现特殊接口和所有POJO(普通Java对象)的类。
  3. spring-orm模块为流行的对象关系映射 API 提供了集成层 ,包括JPA和 Hibernate。使用spring-orm模块,您可以将这些O / R映射框架与Spring提供的所有其他功能(如前面提到的简单的声明式事务管理功能)结合使用。
  4. spring-oxm模块提供了支持JAXB,Castor,JiBX和XStream等对象/ XML映射实现的抽象层。
  5. spring-jms模块(Java消息服务)包含用于生成和使用消息的功能。自Spring Framework 4.1以来,它提供了与spring-messaging模块的集成 。

Web

网络层由 spring-web, spring-webmvc and spring-websocket 模块组成。

  1. spring-web模块提供基本的面向Web的集成功能,如多部分文件上传功能,使用Servlet侦听器的IoC容器的初始化以及面向Web的应用程序上下文。它还包含一个HTTP客户端和Spring远程处理支持的Web相关部分。

  2. spring-webmvc模块(也称为Web-Servlet模块)包含Spring的模型 - 视图 - 控制器(MVC)和Web应用程序的REST Web服务实现。Spring的MVC框架提供了域模型代码和Web表单之间的清晰分离,并且与Spring框架的所有其他功能集成在一起。

Test(测试)

spring-test模块支持使用 JUnit 或 TestNG 对 Spring 组件进行单元测试和 集成测试。它提供了一致的Spring 的加载 ApplicationContext 和这些上下文的缓存。它还提供了模拟对象,您可以使用它来单独测试您的代码。

1. AOP

1.1 OOP(面向对象编程)

比如C语言是采用面向过程来写代码的,但在企业级开发中,重复代码会有很多,而业务场景对应的恰恰是一些生活中的事物,同一类事物,必然会有一些共同点(比如:人、桌子、合同..)那么OOP就是将事物再代码中对应成对象,从而减少冗余,方便了代码的统一管理,易扩展。由于继承、封装、多态的特性,自然设计出高内聚、低耦合的系统结构,使得系统更灵活…

由事物的共同属性 —抽象成了–> 对象

1.2 AOP(面向切面编程)

AOP 采用横向抽取机制,取代了传统纵向继承体系的重复代码.在运行期通过代理方式向目标类织入增强代码。

image.png

横向抽取 ?
比如‘人’这个对象,由于都有身高体重等等属性..于是我们抽象成了OOP。然后再企业开发中,我有一些需求:

  • 这个人一吃饭(运行:eat方法)就输出一个Log日志
  • 这个人一登录系统(运行:login方法)就先来判断权限身份是否正确
  • 这个人一睡觉(运行:sleep)就停止某些应用的运行

你可能会说ok没问题,写在方法后面、用继承、用工厂模式!
其实这些并不适用,在敏捷开发的今天,产品需求可能会不断改动、拓展!
那么在修改、或者新增删除这种方法的时候以上就会改动较大。AOP就是来解决这个问题的。

由事物的共同方法 —抽象成了–> 织面
或者直接说 统一管理了在某一个情况下都要执行的方法:日志、鉴权、配置等

1.3 AOP 使用

AspectJ (推荐)

它是一个基于Java语言的AOP框架,Spring 2.0以后新增了对AspectJ切点表达式支持。是基于注解方式的,比较方便的。

  1. pom -> aspectjweaver
  2. 切面类上加注解 -> @Aspect
  3. 找切点 -> execution(* top.hopesattion.ProductDao.save(..))"
  4. 定义前置通知 -> @Before
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 切面类
*/
@Aspect
public class Demo {
/**
* 前置通知:在 ProductDao.save 方法之前运行
* value 定义切入点:在save的时候进行校验
* JoinPoint 获得切点信息
*/
@Before(value = "execution(* top.hopesattion.ProductDao.save(..))")
public void before(JoinPoint joinPoint) {
System.out.println("----before 日志、鉴权、配置等操作可以在这执行---" + joinPoint);
}
}

通知类型

@Before 前置通知,相当于BeforeAdvice

@AfterReturning 后置通知,相当于AfterReturningAdvice

@Around 环绕通知,相当于MethodInterceptor

@AfterThrowing 异常抛出通知,相当于ThrowAdvice

@After 最终final通知,不管是否异常,该通知都会执行

切入点

在lue处定义

语法:execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>

切点的另一种定义方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//每个通知内定义切点,会造成工作量大,不易维护,对于重复的切点,可以使用@Pointcut进行定义
//统一定义,方便管理和使用
//myPointcut1
@Pointcut(value = "execution(* com.prim.aspectj.ProductDao.save(..))")
private void myPointcut1() {
}
//myPointcut2
@Pointcut(value = "execution(* com.prim.aspectj.ProductDao.update(..))")
private void myPointcut2() {
}
//value处直接调用
@Before(value = "myPointcut1()||myPointcut2()")
public void before(JoinPoint joinPoint) {
System.out.println("--before--" + joinPoint);
}

AspectJ 也可以基于XML来进行配置AOP,不太推荐就不介绍了。

1.4 AOP 原理

Java 动态代理。

具体有如下四步骤:

  1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
  2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
  3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
  4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

GCLIB代理

  • cglib(Code Generation Library )是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
  • cglib封装了asm,可以在运行期动态生成新的class。
  • cglib用于AOP,jdk中的proxy必须基于接口,cglib却没有这个限制。>

原理区别:

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

Spring使用的是哪种代理?

Spring在运行期,生成动态代理对象,不需要特殊的编辑器

Spring AOP的底层就是通过JDK动态代理或CGlib动态代理技术为目标bean执行横向织入

  1. 若目标对象实现了若干接口,Spring使用JDK的java.lang.reflect.Proxy类代理,

    (通过配置可强制使用CGLIB实现AOP)

  2. 若目标对象没有实现任何接口,Spring使用CGlib库生成目标对象的子类

程序中应该优先对接口创建代理,便于程序解耦维护

Spring只支持方法连接点,不提供属性连接点

标记的final方法,不能被代理,因为无法进行覆盖

  1. JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
  2. CGlib是针对目标类生产子类,因此类或方法不能使final的

如何强制使用CGLIB实现AOP?

  • 添加CGLIB库,SPRING_HOME/cglib/*.jar
  • 在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class=”true”/>

2. IOC

IOC【Inversion of Control】 控制反转

  • 控制:指的是对象创建(实例化、管理)的权利

  • 反转:控制权交给外部环境了(spring框架、IoC容器)

  • 传统开发⽅式:⽐如类A依赖于类B,往往会在类A中new⼀个B的对象

  • IoC思想下开发⽅式:我们不⽤⾃⼰去new对象了,⽽是由IoC容器(Spring框架)去帮助我们实例化对象,并且管理它的内部的依赖关系。

参考文献

动态代理:https://www.jianshu.com/p/c97f1f83171f

Prev
2022-09-22 22:42:48
Next