一.简介
1.1.背景
Spring是一个开源框架,提供了一种全面的、一致的编程模型,用于构建企业级Java应用程序。它能够帮助开发者快速构建可扩展和易于维护的应用程序,并提供了丰富的功能库和工具,以支持各种企业级应用开发需求。
Spring框架最初由Rod Johnson于2003年创建,目的是简化企业级Java开发,并引入了面向切面编程(AOP)的概念。Spring的核心特性包括依赖注入(DI)和控制反转(IoC),它们使开发者能够更灵活地管理和配置应用程序的组件。
Spring框架提供了许多模块和扩展,每个模块都专注于不同的方面,例如Web应用程序开发、数据访问、安全性、消息传递等等。这些模块可以根据项目需求进行选择和集成,使开发人员能够轻松构建各种类型的应用程序。
目的:解决企业应用开发的复杂性
功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
范围:任何Java应用
简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
1.2.Spring框架的核心
- 依赖注入(Dependency Injection,DI):DI是Spring框架的核心概念之一。它通过将对象之间的依赖关系交给容器管理,从而降低了组件之间的耦合度。开发者只需要定义好对象的依赖关系,而不需要关心如何获取依赖,这使得代码更具灵活性和可测试性。
- 控制反转(Inversion of Control,IoC):IoC是DI的实现方式,它实现了反转了对象的控制权。在Spring框架中,应用程序的控制权被转移到了Spring容器中,容器负责创建和管理对象的生命周期,开发者只需要关注业务逻辑的实现。
- AOP(面向切面编程):AOP是Spring框架的另一个核心概念。它通过将跨越多个组件的关注点(如日志记录、事务管理等)从业务逻辑中解耦出来,提供了一种非侵入式的方式来增强应用程序的功能。Spring框架提供了AOP的实现,开发者可以通过配置或注解来定义切面和通知,将横切关注点应用于应用程序中的方法或类。
- Spring容器(ApplicationContext):Spring容器是Spring框架的核心容器,负责创建和管理对象的生命周期。它通过读取配置文件或基于注解来实例化和组装对象,并提供了依赖注入和控制反转的支持。Spring容器提供了多种不同类型的容器,如ClasspathXmlApplicationContext、AnnotationConfigApplicationContext等,可以根据项目需求选择合适的容器。
二.Spring ioc的容器的特点
2.1.ioc的理解
- IoC(Inversion of Control)是Spring框架的核心概念之一,也被称为控制反转。它是一种设计原则,用于解耦应用程序中的组件关系,使得代码更加灵活、可扩展、可测试和可维护。
- Spring中的IoC是通过Spring容器实现的。Spring容器负责实例化和组装对象,它会读取配置文件或基于注解来识别和创建对象,同时自动处理对象之间的依赖关系。开发者只需要通过注解或XML配置文件来描述对象之间的关系,Spring框架会根据配置信息对对象进行实例化和注入。
- 通过IoC,开发者可以实现松耦合的组件设计,使得代码更具可维护性和可扩展性。同时,IoC也为AOP(面向切面编程)提供了基础,使得开发者可以更容易地在应用程序中实现横切关注点的功能,如日志、事务管理等。
2.2.ioc的特点
实例化对象的权力由程序员转变为Spring IoC容器。
2.3.ioc的优势
- 解耦:组件之间的耦合度降低,使得代码更易于理解、扩展和维护。
- 可测试性:通过依赖注入可以轻松替换依赖对象,使单元测试更容易实现。
- 灵活性:可以在运行时动态修改依赖关系,而不需要修改代码。
- 可重用性:组件的逻辑和依赖可以被多个应用重复使用。
2.4.案例演示
在进行案例演示前我们需要进行项目对象模型的配置,如下:
pom.xml:
<?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>org.example</groupId> <artifactId>testspring</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>testspring Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <spring.version>5.0.1.RELEASE</spring.version> <javax.servlet.version>4.0.0</javax.servlet.version> <junit.version>4.12</junit.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- 2、导入spring依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <!-- 5.1、junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- 5.2、servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${javax.servlet.version}</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>testspring</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
UserService接口:
package com.junlinyi.ioc.service; /** * @author JunLinYi * @site www.JunLinYi.com * @company 君氏集团 * @create 2023-08-15-14:50 * * 用户更改个人信息的接口 */ public interface UserService { public void update(); }
UserServiceImpl1:
package com.junlinyi.ioc.service.impl; import com.junlinyi.ioc.service.UserService; /** * @author JunLinYi * @site www.junlinyi.com * @company 君氏集团 * @create 2023-08-15-14:52 * * 客户的需求 * 需求:客户在登录后需要具备更改个人信息的功能 * * 场景1: * 客户要求,在新增的需求上做迭代版本,如上传头像 * * 场景2: * ... * 客户要求,在新增的需求上做优化,提升性能,如使用多线程 */ public class UserServiceImpl1 implements UserService { public void update() { System.out.println("更改个人用户信息(普通用户功能)"); //添加上传头像功能的代码 // System.out.println("上传头像的功能"); } }
UserServiceImpl2:
package com.junlinyi.ioc.service.impl; import com.junlinyi.ioc.service.UserService; /** * @author JunLinYi * @site www.JunLinYi.com * @company 君氏集团 * @create 2023-08-15-14:52 * * 客户的需求 * 需求:客户在登录后需要具备更改个人信息的功能 * * 场景1: * 客户要求,在新增的需求上做迭代版本,如上传头像 * * 场景2: * ... * 客户要求,在新增的需求上做优化,提升性能,如使用多线程 */ public class UserServiceImpl2 implements UserService { public void update() { System.out.println("更改个人用户信息(普通用户功能)"); //添加上传头像功能的代码 System.out.println("上传头像的功能(会员用户功能)"); } }
UserAction:
package com.junlinyi.ioc.web; import com.junlinyi.ioc.service.UserService; /** * @author JunLinYi * @site www.JunLinYi.com * @company 君氏集团 * @create 2023-08-15-15:04 * * 程序员手动实例化对象的弊端: * 1.一旦依赖的接口的实现需要大批量改动,迭代,维护的成本极高 * 2.当接口的实现类不同时,维护的成本高 */ public class UserAction { private UserService userService; public UserService getUserService() { return userService; } public void setUserService(UserService userService) { this.userService = userService; } public String updata(){ userService.update(); return "list"; } }
GoodsAction:
package com.junlinyi.ioc.web; import com.junlinyi.ioc.service.UserService; /** * @author JunLinYi * @site www.JunLinYi.com * @company 君氏集团 * @create 2023-08-15-15:09 */ public class GoodsAction { private UserService userService; public UserService getUserService() { return userService; } public void setUserService(UserService userService) { this.userService = userService; } public String updata(){ userService.update(); return "list"; } }
spring-context.xml:
<?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"> <!-- 凡是在Spring配置文件spring-context.xml中配置,那么该类javabean就交给了Spring容器管理--> <bean class="com.junlinyi.ioc.web.UserAction" id="userAction"> <property name="userService" ref="userService"></property> </bean> <bean class="com.junlinyi.ioc.web.GoodsAction" id="goodsAction"> <property name="userService" ref="userServiceImpl1"></property> </bean> <bean class="com.junlinyi.ioc.service.impl.UserServiceImpl2" id="userService"></bean> <bean class="com.junlinyi.ioc.service.impl.UserServiceImpl1" id="userServiceImpl1"></bean> </beans>
Demo1测试类:
package com.junlinyi.ioc.demo; import com.junlinyi.ioc.web.GoodsAction; import com.junlinyi.ioc.web.UserAction; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author JunLinYi * @site www.JunLinYi.com * @company 君氏集团 * @create 2023-08-15-15:42 */ public class Demo1 { public static void main(String[] args) { //加载Spring核心配置文件(建模),获取Spring的上下文对象,上下文对象中可以获取任何javabean对象 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring-context.xml"); UserAction userAction = (UserAction) context.getBean("userAction"); userAction.updata(); System.out.println("********************"); GoodsAction goodsAction = (GoodsAction) context.getBean("goodsAction"); goodsAction.updata(); } }
演示效果:
三.Spring的注入方式
3.1.set注入
将GoodsAction中的所有代码修改为以下代码:
package com.junlinyi.ioc.web; import com.junlinyi.ioc.service.UserService; import java.util.List; /** * @author JunLinYi * @site www.JunLinYi.com * @company 君氏集团 * @create 2023-08-15-15:09 */ public class GoodsAction { /** * 例如:在不同的控制器中进行方法调用 */ private UserService userService; private String gname;//名称 private int age;//保质期 private List<String> peoples;//使用人群 public String getGname() { return gname; } public void setGname(String gname) { this.gname = gname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public List<String> getPeoples() { return peoples; } public void setPeoples(List<String> peoples) { this.peoples = peoples; } public UserService getUserService() { return userService; } public void setUserService(UserService userService) { this.userService = userService; } public void pop(){ System.out.println("名称:"+this.gname); System.out.println("保证期:"+this.age); System.out.println("使用人群:"+this.peoples); } public String update(){ userService.update(); return "list"; } }
再修改spring-context.xml配置文件:
<?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"> <!-- 凡是在Spring配置文件spring-context.xml中配置,那么该类javabean就交给了Spring容器管理--> <bean class="com.junlinyi.ioc.web.UserAction" id="userAction"> <property name="userService" ref="userService"></property> </bean> <bean class="com.junlinyi.ioc.web.GoodsAction" id="goodsAction"> <property name="userService" ref="userServiceImpl1"></property> <property name="gname" value="小文"></property> <property name="age" value="19"></property> <property name="peoples"> <list> <value>印度飞饼</value> <value>意大利炮</value> <value>北京烤鸭</value> <value>墨西哥卷</value> </list> </property> </bean> <bean class="com.junlinyi.ioc.service.impl.UserServiceImpl2" id="userService"></bean> <bean class="com.junlinyi.ioc.service.impl.UserServiceImpl1" id="userServiceImpl1"></bean> </beans>
最后返回demo测试类执行结果,如下:
3.2.构造注入
将User Action中的代码修改成以下代码:
package com.junlinyi.ioc.web; import com.junlinyi.ioc.service.UserService; import java.util.List; /** * @author JunLinYi * @site www.JunLinYi.com * @company 君氏集团 * @create 2023-08-15-15:04 * * 程序员手动实例化对象的弊端: * 1.一旦依赖的接口的实现需要大批量改动,迭代,维护的成本极高 * 2.当接口的实现类不同时,维护的成本高 */ public class UserAction { private UserService userService ; private String uname;//姓名 private int age;//年龄 private List<String> hobby;//爱好 public UserAction() { } public UserAction(String uname, int age, List<String> hobby) { this.uname = uname; this.age = age; this.hobby = hobby; } public UserService getUserService() { return userService; } public void setUserService(UserService userService) { this.userService = userService; } public void pop(){ System.out.println("名字为:"+this.uname); System.out.println("年龄为:"+this.age); System.out.println("爱好为:"+this.hobby); } public String updata(){ userService.update(); return "list"; } }
再修改spring-context.xml 配置文件,如下:
<?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"> <!-- 凡是在Spring配置文件spring-context.xml中配置,那么该类javabean就交给了Spring容器管理--> <bean class="com.junlinyi.ioc.web.UserAction" id="userAction"> <property name="userService" ref="userService"></property> <constructor-arg name="uname" value="扎克" ></constructor-arg> <constructor-arg name="age" value="18" ></constructor-arg> <constructor-arg name="hobby"> <list> <value>唱,跳</value> <value>Rap</value> <value>篮球</value> </list> </constructor-arg> </bean> <bean class="com.junlinyi.ioc.web.GoodsAction" id="goodsAction"> <property name="userService" ref="userServiceImpl1"></property> <property name="gname" value="小文"></property> <property name="age" value="19"></property> <property name="peoples"> <list> <value>印度飞饼</value> <value>意大利炮</value> <value>北京烤鸭</value> <value>墨西哥卷</value> </list> </property> </bean> <bean class="com.junlinyi.ioc.service.impl.UserServiceImpl2" id="userService"></bean> <bean class="com.junlinyi.ioc.service.impl.UserServiceImpl1" id="userServiceImpl1"></bean> </beans>
最后返回demo测试类执行结果,结果如下:
3.3.接口注入
自动装配:byName byType
byName:javaBean会根据属性名在spring的上下文中的bean的id进行查找,只要有就会自动装配
修改spring-context..xml配置文件,如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" default-autowire="byName" 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"> <!-- 凡是在Spring配置文件spring-context.xml中配置,那么该类javabean就交给了Spring容器管理--> <bean class="com.junlinhyi.ioc.web.UserAction" id="userAction"> <property name="userService" ref="userService"></property> <!-- <constructor-arg name="uname" value="扎克" ></constructor-arg>--> <!-- <constructor-arg name="age" value="18" ></constructor-arg>--> <!-- <constructor-arg name="hobby">--> <!-- <list>--> <!-- <value>唱,跳</value>--> <!-- <value>Rap</value>--> <!-- <value>篮球</value>--> <!-- </list>--> <!-- </constructor-arg>--> </bean> <bean class="com.junlinhyi.ioc.web.GoodsAction" id="goodsAction"> <property name="userService" ref="userServiceImpl1"></property> <!-- <property name="gname" value="小文"></property>--> <!-- <property name="age" value="19"></property>--> <!-- <property name="peoples">--> <!-- <list>--> <!-- <value>印度飞饼</value>--> <!-- <value>意大利炮</value>--> <!-- <value>北京烤鸭</value>--> <!-- <value>墨西哥卷</value>--> <!-- </list>--> <!-- </property>--> </bean> <bean class="com.junlinhyi.ioc.service.impl.UserServiceImpl2" id="userService"></bean> <bean class="com.junlinhyi.ioc.service.impl.UserServiceImpl1" id="userServiceImpl1"></bean> </beans>
测试结果:
注:如果名称不同或者没有改名称将会有空指针报错(null值报错)
byType:JavaBean会议根据属性名对应的接口,在spring上下文中进行查找
查找方式:是根据spring上下文中是否有接口实现类进行匹配,只要有就自动配置。
修改spring-context.xml 配置文件,如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" default-autowire="byType" 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"> <!-- 凡是在Spring配置文件spring-context.xml中配置,那么该类javabean就交给了Spring容器管理--> <bean class="com.junlinyi.ioc.web.UserAction" id="userAction"> <property name="userService" ref="userService"></property> <!-- <constructor-arg name="uname" value="扎克" ></constructor-arg>--> <!-- <constructor-arg name="age" value="18" ></constructor-arg>--> <!-- <constructor-arg name="hobby">--> <!-- <list>--> <!-- <value>唱,跳</value>--> <!-- <value>Rap</value>--> <!-- <value>篮球</value>--> <!-- </list>--> <!-- </constructor-arg>--> </bean> <bean class="com.junlinyi.ioc.web.GoodsAction" id="goodsAction"> <property name="userService" ref="userServiceImpl1"></property> <!-- <property name="gname" value="小文"></property>--> <!-- <property name="age" value="19"></property>--> <!-- <property name="peoples">--> <!-- <list>--> <!-- <value>印度飞饼</value>--> <!-- <value>意大利炮</value>--> <!-- <value>北京烤鸭</value>--> <!-- <value>墨西哥卷</value>--> <!-- </list>--> <!-- </property>--> </bean> <bean class="com.junlinyi.ioc.service.impl.UserServiceImpl2" id="userService"></bean> <bean class="com.junlinyi.ioc.service.impl.UserServiceImpl1" id="userServiceImpl1"></bean> </beans>
结果为:
注:如果没有或者有两个以上的接口实现类将会报错,因为是自动查询如有多个将不知道是哪个。