自述:此篇文章主要记录了本人学习Spring的日常,在优快云上发表,一是为了方便今后回顾,二也是想分享给有需要的人。
目录
1.简介
Spring是一种开源的应用程序框架,最初由Rod Johnson在2003年创建。它提供了一种简化企业级Java应用开发的方式。Spring框架以依赖注入(DI)和面向切面编程(AOP)为核心思想,旨在提供灵活、可扩展、模块化和松耦合的开发环境。
2.Spring的优点
-
松耦合:Spring框架通过依赖注入(DI)和控制反转(IoC)容器来管理应用程序中的对象和组件之间的依赖关系。这种松耦合的设计使得应用程序的各个模块能够独立开发、测试和维护,并且易于扩展和重用。
-
面向切面编程(AOP)支持:Spring框架提供了面向切面编程的支持,可以将与业务逻辑无关的横切关注点(如日志记录、事务管理、安全性等)从核心业务逻辑中分离出来,提高了代码的可读性、可维护性和可测试性。
-
简化开发:Spring框架提供了大量的功能和模块,如Spring MVC、Spring Data、Spring Security等,可以帮助开发人员快速构建各种类型的应用程序。此外,Spring还提供了许多便捷的特性,如声明式事务管理、表单验证、数据绑定等,简化了开发过程。
-
高度灵活:Spring框架采用了模块化的设计,开发人员可以根据自己的需求选择和配置所需的功能模块。这种灵活性使得Spring框架非常适合各种规模和类型的应用程序开发,并且能够与其他流行的框架和技术(如Hibernate、MyBatis等)无缝集成。
-
测试支持:Spring框架提供了广泛的测试支持,包括单元测试、集成测试和模拟测试等。通过使用Spring的测试支持类和工具,开发人员可以更轻松地编写可靠的自动化测试,并验证应用程序的正确性和性能。
-
强大的社区支持:作为一个开源框架,Spring拥有庞大的社区支持。开发人员可以从Spring社区获取到丰富的文档、示例代码和第三方库,解决问题和获得反馈。此外,Spring框架还定期发布更新版本,保持与最新的Java开发技术的兼容性。
3.Spring体系结构
Spring框架的体系结构是基于分层和模块化设计的,它由多个模块组成,每个模块负责不同的功能和特性。以下是Spring框架的主要组件和体系结构:
-
Spring Core:Spring核心模块提供了IoC容器和依赖注入功能。IoC(Inversion of Control,控制反转)将对象的创建、组装和管理的责任转移到框架中,降低了组件之间的耦合度。依赖注入(DI)通过配置文件或注解将组件之间的依赖关系注入到对象中,使得对象之间的协作更加灵活和可扩展。
-
Spring MVC:Spring MVC(Model-View-Controller)是基于MVC设计模式的Web开发框架。它通过DispatcherServlet来接收和处理用户请求,并将请求路由到相应的处理器(Controller)。Controller处理请求后生成模型数据(Model),然后将数据传递给视图(View)进行渲染,最终返回给用户。Spring MVC提供了强大的请求处理、视图解析、数据绑定等功能,使得开发Web应用程序更加高效和灵活。
-
Spring Data:Spring Data模块简化了与各种数据存储技术(如关系数据库、NoSQL数据库、搜索引擎等)的集成。通过Spring Data模块,开发人员可以使用简单的API和注解来访问和操作数据存储,而不用关心底层的实现细节。Spring Data支持多种数据访问技术,如JPA、Hibernate、MongoDB、Redis等。
-
Spring Security:Spring Security模块提供了身份认证和访问控制的功能,帮助开发人员保护应用程序的安全性。它支持各种认证机制(如基于表单、基本认证、OAuth等),并且可以进行细粒度的权限控制和安全配置。Spring Security还集成了其他Spring框架模块,如Spring MVC和Spring Core,以提供全面的安全解决方案。
-
Spring AOP:Spring AOP(Aspect-Oriented Programming)模块支持面向切面编程,通过在不同的关注点(如日志、事务管理、安全性等)上横切应用程序的逻辑,提供了更好的代码可读性和可维护性。Spring AOP采用声明式的方式,开发人员可以通过配置或注解来定义切面和通知,将其应用到目标对象中。
除了以上核心模块外,Spring框架还包含其他模块,如Spring Batch(批处理)、Spring Integration(集成)、Spring Cloud(云原生开发)等,用于满足不同领域和需求的开发。这些模块共同构成了Spring框架的体系结构,提供了丰富的功能和扩展性,使得开发人员能够构建灵活、可维护和可扩展的应用程序。
4.Spring设计理念
Spring的设计理念可以概括为以下几点:
-
轻量级:Spring框架采用了轻量级的设计方式,尽可能减少对系统资源的占用,使得应用程序可以快速启动并运行。它只需要很少的配置信息,而且对于开发者来说也非常简单易用。
-
松耦合:Spring通过依赖注入(DI)和面向接口编程的方式,实现了组件之间的松耦合。应用程序的不同模块可以独立开发、测试和维护,降低了系统的复杂性,并提高了代码的可重用性和可扩展性。
-
面向切面编程(AOP):Spring框架支持AOP编程,可以将一些与业务逻辑无关的横切关注点(如日志记录、事务管理等)从应用程序的主要业务逻辑中解耦出来,通过配置的方式,将这些关注点以切面的方式插入到应用程序的执行流程中。
-
容器化:Spring框架提供了一个IoC容器,即控制反转容器,负责创建和管理对象的生命周期。通过IoC容器,可以将应用程序的对象的创建和依赖关系的管理交给Spring框架来完成,大大简化了开发工作,并提高了代码的可测试性和可维护性。
-
综合性:Spring框架提供了众多的功能模块,涵盖了从应用程序的基础设施层(如数据访问、事务管理、安全性等)到业务逻辑层的各个方面。开发者可以根据自己的需求选择需要的模块,灵活地构建自己的应用程序。
总体而言,Spring的设计理念是以简单、灵活和可扩展为核心,通过提供一系列的功能模块和设计原则,帮助开发者更加高效地开发企业级应用程序。
5.IOC(控制反转)
1.IOC概念
IOC(Inversion of Control,控制反转)是一种软件设计原则,也是Spring框架的核心特性之一。它是指将对象的创建、依赖关系的管理和生命周期的控制交给容器来完成,而不是由开发者手动管理。
传统的程序设计中,对象之间的依赖关系是通过直接实例化对象或使用工厂类来管理的。这样的设计使得对象之间高度耦合,导致代码难以维护、扩展和测试。
而在IOC的设计理念下,对象的创建和依赖关系的管理被转移到了一个独立的容器中,容器负责根据配置信息创建对象并进行依赖注入。开发者只需要提供配置信息,告诉容器哪些对象需要被创建,以及它们之间的依赖关系,而无需关心对象的具体创建和管理过程。
通过IOC,对象之间的耦合度大大降低,代码变得更加灵活、可扩展和可测试。开发者可以专注于业务逻辑的实现,而不用过多关注对象的创建和依赖管理的细节。
Spring框架提供了一个IOC容器,即控制反转容器,负责管理对象的生命周期、依赖关系的注入等。开发者只需要通过配置文件或注解的方式,告诉Spring框架如何创建和管理对象,即可实现IOC的效果。
总结起来,IOC是一种通过将对象的创建和依赖关系的管理交给容器来完成的设计原则,它能够降低对象之间的耦合度,提高代码的可维护性和可测试性。Spring框架通过提供IOC容器,帮助开发者更加方便地实现IOC的效果。
2.DI概念
DI(Dependency Injection,依赖注入)是一种实现控制反转(IOC)的具体技术手段。它是指在对象创建的过程中,将对象所依赖的其他对象的引用通过外部注入的方式传递给对象,从而解耦对象之间的依赖关系。
传统的程序设计中,对象通常通过直接实例化或使用工厂类来创建其他对象并管理它们的依赖关系。这种方式使得对象之间紧密耦合,导致代码的可测试性和可维护性降低。
而通过DI的方式,对象不再负责自己依赖对象的创建和管理,而是通过外部容器来完成。容器负责在对象创建时,自动将对象所依赖的其他对象的引用注入进来,从而满足对象的依赖需求。
DI可以通过构造函数注入、属性注入或方法注入等方式实现。在构造函数注入中,对象通过构造函数的参数来声明依赖关系,并在创建对象时由容器自动注入所需的依赖;在属性注入中,对象通过公开的属性来声明依赖关系,并在对象创建后由容器注入相应的依赖;在方法注入中,对象通过特定的方法来声明依赖关系,并在创建对象后由容器调用该方法,传入所需的依赖。
DI的好处是降低了对象之间的耦合度,使得代码更加灵活、可扩展和可测试。它也促进了单一责任原则的实践,每个对象只需要关注自身的核心功能,而不用关心依赖对象的创建和管理细节。
Spring框架是一个广泛使用DI的框架,它通过提供IOC容器来实现依赖注入。开发者只需要在配置文件或注解中声明对象的依赖关系,Spring框架就会自动完成对象的创建和依赖注入。
总结起来,DI是一种通过外部注入的方式,将对象所依赖的其他对象的引用传递给对象的技术手段。它能够解耦对象之间的依赖关系,提高代码的可维护性和可测试性。Spring框架是一个广泛使用DI的框架,通过提供IOC容器来实现依赖注入。
3.基本使用
1.引入Spring依赖:在项目的构建工具(如Maven)配置文件中添加Spring框架的依赖,例如:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- 2.Spring dao依赖 -->
<!-- spring-jdbc包括了一些如jdbcTemplate的工具类 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- 3.Spring web依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- 4.Spring test依赖:方便做单元测试和集成测试 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
2.创建Spring配置文件:在项目中创建一个Spring的配置文件,命名为applicationContext.xml
,并放置在classpath下(src/main/resources目录)。配置文件用于声明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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
3.声明Bean对象:在applicationContext.xml
中,使用<bean>
元素来声明需要被IOC容器管理的Bean对象。可以指定Bean的类名、ID、作用域等属性。例如:
<bean id="myBean" class="com.example.MyBean">
<!-- 可以在这里配置Bean的属性 -->
</bean>
4.注入依赖:使用IOC容器将对象的依赖关系注入到相应的Bean中。有以下几种常见的注入方式:
set注入:通过调用目标对象的setter方法,将依赖对象传递给目标对象进行注入。
<bean id="user" class="com.domain.User">
<property name="name" value="小王"/>
<property name="password" value="123456"/>
</bean>
构造函数注入:在<bean>
标签内部使用<constructor-arg>
子标签,并指定所需依赖对象的引用或值。例如:
<bean id="userMapper" class="com.mapper.impl.UserMapperImpl"></bean>
<bean id="userService" class="com.service.impl.UserServiceImpl">
<constructor-arg ref="userMapper"/> <!-- 通过引用注入依赖对象 -->
<!-- 或者使用值注入 -->
<!-- <constructor-arg value="userMapper"/> -->
</bean>
注解注入:在Bean类中使用注解来标识需要注入的属性或构造函数参数。例如:
@Component
public class MyBean {
@Autowired
private OtherBean otherBean;
// ...
}
5.获取Bean对象:通过IOC容器获取所需的Bean对象。可以使用ApplicationContext
接口提供方法,根据Bean的ID或类型来获取相应的Bean实例。例如,在Java代码中获取Bean实例:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyBean myBean = context.getBean("myBean", MyBean.class);
// 使用获取到的Bean对象进行相关操作
}
}
通过以上步骤和示例代码,就可以实现Spring框架中IOC的基本使用。注意要将示例代码中的包名、类名和配置文件名修改为适合你项目的命名规范。同时,确保配置文件applicationContext.xml
位于正确的路径下,并包含正确的Bean声明和依赖注入配置。
6.AOP(面向切面)
1.概念
AOP(Aspect-Oriented Programming)是一种编程范式,旨在通过将横切关注点(如日志记录、事务管理、安全性等)与核心业务逻辑分离来提高代码的模块化和可维护性。它通过将这些横切关注点定义为切面,并在运行时将切面织入到应用程序的目标对象中,实现对横切逻辑的集中管理和配置。
传统的面向对象编程以纵向划分,即将功能按照类和对象的层次结构进行划分,但无法很好地处理那些会跨越多个类和对象的横切关注点。而AOP则以横向切分的方式,将关注点从核心业务逻辑中解耦出来,以切面的形式进行统一的管理。
AOP的核心思想是通过定义切面(Aspect)来描述横切关注点,包括切点(Pointcut)和通知(Advice)。切点定义了在应用程序执行过程中哪些位置插入横切逻辑,通知定义了在切点处执行的具体操作。当应用程序运行时,AOP框架会动态地将切面织入到目标对象的连接点上,从而实现对横切逻辑的有效管理和执行。
2.AOP的优点
- 模块化:将横切关注点封装成可复用的模块,避免代码重复。
- 解耦:将横切逻辑与核心业务逻辑分离,提高代码的可维护性和可测试性。
- 简化代码:集中处理横切关注点,使核心业务逻辑更加简洁。
- 集中管理:通过切面对横切逻辑进行统一管理和配置。
- 动态织入:在运行时动态地将切面织入到目标对象中,提供灵活的配置和修改能力。
3.AOP相关术语
-
切面(Aspect):切面是一个模块化单元,用于封装特定的横切关注点和处理逻辑。它由切点和通知组成。
-
切点(Pointcut):切点是指在应用程序执行过程中,定义在何处插入横切逻辑的规则或条件。切点可以根据方法名称、参数、类名等匹配规则进行定义。
-
通知(Advice):通知定义了在切点处执行的具体操作。常见的通知类型包括前置通知(Before)、后置通知(After)、异常通知(AfterThrowing)、返回通知(AfterReturning)和环绕通知(Around)。
-
连接点(Join Point):连接点是应用程序执行过程中可以插入横切逻辑的特定位置。例如,在方法调用、方法执行、异常处理等时刻都可以作为连接点。
-
织入(Weaving):织入是将切面应用到目标对象中的过程。织入可以在编译时、加载时或运行时进行。在织入过程中,切面的横切逻辑会被动态地插入到应用程序的相应连接点上。
-
引入(Introduction):引入是AOP中的一种机制,用于向现有的类或对象添加新的接口和实现。通过引入,可以在不修改原有代码的情况下,为对象动态地添加新的功能。
-
目标对象(Target Object):目标对象是应用程序中真正执行业务逻辑的对象。切面会织入到目标对象中,以实现对横切关注点的管理。
-
代理(Proxy):代理是AOP中的一种机制,用于控制对目标对象的访问。当调用目标对象时,代理会拦截方法调用,并根据配置的切面逻辑来执行相应的通知。
-
组件扫描(Component Scanning):组件扫描是一种自动化配置方式,用于在应用程序中自动发现和注册带有特定注解的组件,如切面、切点和通知。
4.AOP的五种增强
AOP(面向切面编程)中的增强(Advice)是指在目标方法或连接点执行时插入的横切逻辑。根据插入的时机和方式,AOP中常见的增强类型包括以下几种:
-
前置增强(Before Advice):在目标方法执行之前执行的横切逻辑。可以用于执行一些预处理操作,如参数验证、权限检查等。
-
后置增强(After Advice):在目标方法执行之后执行的横切逻辑。可以用于执行一些清理操作,如资源释放、日志记录等。
-
返回增强(After Returning Advice):在目标方法成功返回结果之后执行的横切逻辑。可以用于处理返回值、记录日志等。
-
异常增强(After Throwing Advice):在目标方法抛出异常时执行的横切逻辑。可以用于处理异常、发送通知等。
-
环绕增强(Around Advice):在目标方法执行前后都可以执行的横切逻辑。环绕增强可以完全控制目标方法的执行过程,可以选择是否调用目标方法以及何时调用。
5.AOP的实现
1.引入依赖的jar包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2.编写保存用户的业务代码以及用于增强处理的代码
@Aspect
public class MyAspect {
@Before("execution(* com.cskt.service..*.*(..)))")
public void before(){
System.out.println("前置通知……在方法之前要执行的公共代码放在这里");
}
/**
* 后置通知
* @param returnVal,切点方法执行后的返回值
*/
@AfterReturning(value="execution(* com.cskt.service..*.*(..)))",returning="returnVal")
public void AfterReturning(Object returnVal){
System.out.println("后置通知……"+returnVal);
}
/**
* 环绕通知
* @param joinPoint 可用于执行切点的类
* @return
* @throws Throwable
*/
@Around("execution(* com.cskt.service..*.*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕通知前……");
Object obj=(Object) joinPoint.proceed();
System.out.println("环绕通知后……");
return obj;
}
/**
* 抛出异常
* @param e
*/
@AfterThrowing(value ="execution(* com.cskt.service..*.*(..))",throwing = "e")
public void afterThrowable(Throwable e){
System.out.println("出现异常:msg="+e.getMessage());
}
/**
* 无论什么情况下都会执行的方法
*/
@After(value = "execution(* com.cskt.service..*.*(..))")
public void after(){
//方法的对象的关闭
System.out.println("最终通知……");
}
}
3.编写Spring配置文件
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
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">
<bean id="myaspect" class="com.cskt.aspect.MyAspect"/>
<aop:aspectj-autoproxy/>
</beans>
运行测试