Spring初体验
1.Spring简介
1.1 Spring历史
-
Spring作为当今java开发的框架,与java语言已经密不可分,没有Spring,无法想象开发java程序是多么的工程巨大,Spring将程序开发简化,使得程序开发变得越来越简单。
-
Spring历史:
-
Spring寓意“春天”,就如其名一样,Spring给Java开发乃至整个软件开发行业带来的春天。在Spring框架出来之前,JavaEE 是Sun公司的所制订的EJB框架为标准的。在“遥远”的EJB年代,开发一个EJB需要大量的接口和配置文件,直至EJB 2.0的年代,开发一个EJB还需要配置两个文件,其结果就是配置的工作量比开发的工作量还要大。EJB框架的庞大性与学习难度也比较高,对于软件开发是不利的。
-
Spring框架的前身是interface21(interface21官网),interface21作为Spring的前身,在软件行业也有着起作用。2002年,Rod Johnson(牛人),首次推出了Spring框架的雏形interface21框架。
-
2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,推出了1.0正式版。说到Rod Johnson这个人,也不得不说一下,Rod Johnson是一名悉尼大学的博士。
-
Spring框架有着以下的优点:(以下是官网描述)
(1)Spring 使创建 Java 企业应用程序变得容易。它提供了在企业环境中使用 Java 语言所需的一切,并支持 Groovy 和 Kotlin 作为 JVM 上的替代语言,并且可以根据应用程序的需求灵活地创建多种体系结构。从 Spring Framework 5.0 开始,Spring 需要 JDK 8(Java SE 8)(使用Spring推荐版本),并且已经为 JDK 9 提供了现成的支持。
(2)Spring 支持广泛的应用场景。在大型企业中,应用程序通常存在很长时间,并且必须在升级周期不受开发人员控制的 JDK 和应用程序服务器上运行。其他服务器则可以作为单个 jar 运行,并且服务器可以嵌入云环境中。还有一些可能是不需要服务器的独立应用程序(例如批处理或集成工作负载)。
(3)Spring 是开源的。它拥有一个庞大而活跃的社区,可以根据各种实际用例提供持续的反馈。这帮助 Spring 在很长一段时间内成功地 Developing 了。
-
参考网页:
Spring官网:https://spring.io
Spring中文文档网站:https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/overview.html
github网站:https://github.com/spring-projects/spring-framework
-
1.2 优点:
- Spring是一个开源的免费的框架,容器
- Spring是一个轻量级的框架,是非侵入式的的框架
- Spring的核心是控制反转(IOC),面向切面编程(AOP)
- Spring框架支持事务处理,对其他框架着良好的支持
总结:Spring框架是一个轻量级的,开源的的支持事务处理与有着IOC与AOP的框架(容器)
1.3 Spring框架组成

Spring框架是一个分层的架构,由7个定义良好的模块组成。Spring模块构建在核心容器上,核心容器定义了创建,配置管理和管理bean的方式。

组成Spring框架的每个模块(或组件)都可以单独存在,或者与其他一个或者多个模块联合使用。每个模块的功能如下:
-
Spring Core核心容器:核心容器提供了Spring框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory使用控制反转(IOC)模式将应用程序的配置和依赖性规范与实际的应用程序代码分离。
-
Spring Context:Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,例如:JNDI(ava 命名与目录接口(Java Naming and Directory Interface)),EJB,电子邮件,国际化,校验和调度功能。
-
Spring AOP:通过配置管理特征,Spring AOP模块直接将面向切面(底层实现:动态代理)的编程功能,集成到了Spring框架中。所以,可以很容易的事Spring框架管理支持AOP的对象。Spring AOP模块为基于Spring的应用程序中的对象提供了事务管理服务。通过Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
-
Spring DAO:JDBC DAO抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的异常代码数量(例如打开和关闭连接)。Sprin DAO的面向JDBC的异常遵从通用的DAO异常层次结构。
-
Spring ORM:Sping框架插入了若干个ORM框架,从而提供了ORM到对象关系工具,其中包括JDO(Java数据对象Java Data Objects),Hibernate和iBatis SQL Map。所有这些都遵从Spring的通用事务和DAO异常层次结构。
-
Spring Web模块:Web上下文模块建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文。所以,Spring框架支持与Jakarta Structs的集成。Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
-
Spring Web MVC框架:MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变为高度可配置化,MVC容纳了大量的视图技术,其中包括JSP,Velocity(Velocity是基于Java开发的模板引擎),Tiles,iText和POI。
1.4 扩展
Spring Boot与Spring Cloud
- Spring Boot是Spring的一套快速配置脚手架,可以基于Spring Boot快速开发单个微服务。
- Spring Cloud是基于Spring Boot实现的。
- Spring Boot专注于快速,方便集成的单个微服务个体,Spring Cloud关注全局的的服务整治框架。
- Spring Boot使用了约束大于配置的理念。Spring Booy可以离开Spring Cloud独立开发项目,但是Spring Cloud离不开Spring Boot的支持,属于依赖关系。
- Spring Boot在啊Spring Cloud中起到了承上启下的作用,如果需要学习Spring Cloud,必须需要学习Spring Boot。
2.Spring IOC
我们上面已经简要的介绍了IOC(控制反转),接下来将使用代码与举例方式来更好的了解什么是IOC。
2.1 提要
在介绍Spring IOC之前,我们先来看一个案例:
-
新建一个Maven项目,在使用Spring之前,我们需要导入Spring需要的依赖。依赖我们进入Maven仓库中寻找。
<?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>com.xiaoli</groupId> <artifactId>Spring</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>spring-01-ioc</module> </modules> <dependencies> <!--导入Spring的依赖,我们导入Spring-webmvc依赖是因为webmvc会为我们导入Spring其他依赖的jar包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.9.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> </project> -
以我们之前的dao接口为例,我们在接口中编写以下代码:
-
项目结构图

-
UserDao接口:
package com.xiaoli.dao; //dao接口 public interface UserDao { void getUser(); }UserMysqlDaoImple实现类:
package com.xiaoli.dao; public class UserMysqlDaoImpl implements UserDao{ @Override public void getUser() { System.out.println("UserMysqlDao接口的实现"); } }UserOracleDaoImpl实现类:
package com.xiaoli.dao; public class UserOracleDaoImpl implements UserDao{ @Override public void getUser() { System.out.println("UserOracleDao接口的实现"); } }UserService接口:
package com.xiaoli.Service; //Service接口 public interface UserService { void getUserList(); }UserServiceImpl实现类:
package com.xiaoli.Service; import com.xiaoli.dao.UserDao; import com.xiaoli.dao.UserOracleDaoImpl; public class UserServiceImpl implements UserService{ //Service需要组合Dao private UserDao userDao = new UserOracleDaoImpl(); @Override public void getUserList() { userDao.getUser(); } }测试:
import com.xiaoli.Service.UserService; import com.xiaoli.Service.UserServiceImpl; import org.junit.Test; //传统的方式实现 public class TestTradition { @Test public void test1(){ UserService userService = new UserServiceImpl(); //service层调用dao层 userService.getUserList(); } } -
需求,我们现在需要调用dao到不同实现类:myql与oracle的实现类。
-
第一种解决方法:
我们需要到service层修改我们的源代码,代码的修改权在开发者的手中,主动的修改代码,不符合设计模式中的“开闭原则”,对于需求的变动每一次都要去修改源代码,这是一种”愚蠢“的编码方式。package com.xiaoli.Service; import com.xiaoli.dao.UserDao; import com.xiaoli.dao.UserMysqlDaoImpl; import com.xiaoli.dao.UserOracleDaoImpl; import java.util.Date; public class UserServiceImpl implements UserService{ //Service需要组合Dao // private UserDao userDao = new UserOracleDaoImpl(); private UserDao userDao1 = new UserMysqlDaoImpl(); @Override public void getUserList() { // userDao.getUser(); userDao1.getUser(); } } -
第二种解决方式:我们修改Service层的dao方法,使其可以动态的修改,这个时候,将控制权交予用户之手,用户决定什么时候修改。
UserServiceImple实现类:
package com.xiaoli.Service; import com.xiaoli.dao.UserDao; import com.xiaoli.dao.UserMysqlDaoImpl; import com.xiaoli.dao.UserOracleDaoImpl; import java.util.Date; public class UserServiceImpl implements UserService{ //Service需要组合Dao private UserDao userDao; //使用set方法,动态的修改dao public void setUserDao(UserDao userDao){ this.userDao = userDao; } @Override public void getUserList() { userDao.getUser(); } }测试(用户端)
import com.xiaoli.Service.UserService; import com.xiaoli.Service.UserServiceImpl; import com.xiaoli.dao.UserMysqlDaoImpl; import com.xiaoli.dao.UserOracleDaoImpl; import org.junit.Test; //传统的方式实现 public class TestTradition { @Test public void test1(){ UserService userService = new UserServiceImpl(); //动态的修改需要的dao方法 ((UserServiceImpl)userService).setUserDao(new UserMysqlDaoImpl());//动态变化 //service层调用dao层 userService.getUserList(); //动态的修改需要的dao方法 ((UserServiceImpl)userService).setUserDao(new UserOracleDaoImpl());//动态变化 userService.getUserList(); } }测试结果:

我们是否已经发现了程序出现了什么变化?对,我们将程序修改的主动权交予了用户,使得程序被动的接受用户的改变,程序也会发生相应的改变。
这种实现,从本质上解决了问题,我们程序员不在去管理对象的创建,更多的关注业务代码的实现,使得程序的耦合性更低,大大提高了程序的灵活性,这就是IOC的原型!!!
-
-
2.2 IOC的本质
控制反转IOC(Inversion of Control)是一种设计思想,DI(依赖注入)是实现IOC的一种方法。也有人认为DI只是IOC的另一种说法。在没有IOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全编码在程序中,对象的创建由程序自己控制,控制反转后将对象创建的主动权转移到了第三方。
所以,我们可以暂且的认为,IOC就是:获得依赖对象的方式反转了!!!

- IOC是Spring框架的核心内容,使用多种方式完美的实现了IOC,可以使用XML配置文件,也可以使用注解的方式实现。在Spring最新的版中可以使用零配置实现IOC。
- Spring容器在初始化时先读取配置文件,根据配置文件或者元数据创建于组织对象存入容器中,程序使用时再从容器中取出需要的对象。

在采用XML文件方式配置Bean时,Bean的定义信息和实现是分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
2.3 第一个IOC程序
我们为IOC做了这么多的铺垫,接下来我们就要实现我们的第一个IOC的程序,在这之前,我们采用XML配置文件的方式进行创建。
-
创建一个普通的Maven项目,编写一个实体类为Hello.java

Hello实体类
package com.xiaoli.pojo; //实体类(演示IOC) public class Hello { private String desc; public Hello() { } public Hello(String desc) { this.desc = desc; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } @Override public String toString() { return "Hello{" + "desc='" + desc + '\'' + '}'; } } -
进入官网,拷贝下我们的配置文件,我们为其命名为applicationContext.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> </beans> -
我们在配置文件中将我们的实体类Hello放入到Spring Container(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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 传统创建对象的方式: 1.类型 类型名 = new 类型() Hello hello = new Hello() 2.为对象设置属性: hello.setDesc("Hellow Spring") IOC创建对象的方式:目前我们介绍第一种 1.bean 代表java对象,由spring进行管理,在这里代表Hello类对象 2.id:相当于类型名,可以自定义 3.class:需要创建的类的全限定名(全路径名) IOC设置属性的方法:目前只讲解第一种,后面的几种方法后面介绍 1.property:表示给属性设置值的元素(标签) 2.name:给属性设置值的方法,对于的是setName方法,如果类中没有该方法,就会报错 3.value:设置属性 --> <bean id="hello" class="com.xiaoli.pojo.Hello"> <property name="desc" value="Hello Spring"/> </bean> </beans> -
测试:
import com.xiaoli.pojo.Hello; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; //测试 public class test { @Test public void testIOC(){ //通过配置文件获取应用上下文 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //从上下文中获取对象(通过bean的id) Hello hello = (Hello) context.getBean("hello"); System.out.println(hello); } }-
测试结果:

-
3.DI(依赖注入)
3.1 Spring创建对象方式
3.1.1 通过无参构造方法来创建
-
User实体类
public class User { private int id; private String name; //无参构造函数 public User() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } } -
applicationContext.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--无参数构造方法注入--> <bean id="user" class="User"> <property name="id" value="10"/> <property name="name" value="xiaoli"/> </bean> </beans> -
测试类
import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestDI { @Test public void testDD(){ //无参构造函数注入 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user = context.getBean("user", User.class); System.out.println(user); } }
3.1.2 通过有参构造方法进行注入
-
User实体类
public class User { private int id; private String name; public User() { } //有参构造函数 public User(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } } -
applicationContext.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 有参构造函数注入 1.通过参数下标进行注入 2.通过参数类型进行注入(有局限性性,当多个参数类型相同时) 3.通过参数名进行注入(推荐) --> <bean id="user1" class="User"> <constructor-arg index="0" value="100"/> <constructor-arg index="1" value="xiaowang"/> </bean> <bean id="user2" class="User"> <constructor-arg type="int" value="1000"/> <constructor-arg type="java.lang.String" value="xiaohuai"/> </bean> <bean id="user3" class="User"> <constructor-arg name="id" value="10000"/> <constructor-arg name="name" value="xiaozhang"/> </bean> </beans> -
测试类
import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestDI { @Test public void testDI02(){ //有参构造函数注入 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user1 = context.getBean("user1", User.class); User user2 = context.getBean("user2", User.class); User user3 = context.getBean("user3", User.class); System.out.println(user1); System.out.println(user2); System.out.println(user3); } }
3.2 set方法注入
- set方法进行注入时,必须要有set方法,set方法的方法名由 set + 属性名首字母大写组成;如果属性时boolean类型,没有set方法,是is。
- 普通的set注入方法(注入的值是普通的数据类型)
-
User实体类
public class User { private int id; private String name; public User() { } //有参构造函数 public User(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } } -
applicationContext.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--set方法注入--> <bean id="user4" class="User"> <property name="id" value="50"/> <property name="name" value="xiaoyu"/> </bean> </beans> -
测试
import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestDI { @Test public void testDI03(){ //普通的set方法注入 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user4 = context.getBean("user4", User.class); System.out.println(user4); } }
3.复杂的数据类型的set注入
我们接下来会演示注入list集合,set于map容器一样的数据类型
-
实体类
Teacher类
//实体类teacher public class Teacher { private int id; private String name; public Teacher() { } public Teacher(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Teacher{" + "id=" + id + ", name='" + name + '\'' + '}'; } }Student类
import java.util.*; //实体类Student public class Student { private int id;//Id private String name;//姓名 private Teacher teacher;//老师 private String[] classes;//课程 private Set<String> favor;//爱好 private Map<String,Object> card;//证件 private List<String> friends;//朋友 private String work;//工作 private Properties properties;//文件 public Student() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } public String[] getClasses() { return classes; } public void setClasses(String[] classes) { this.classes = classes; } public Set<String> getFavor() { return favor; } public void setFavor(Set<String> favor) { this.favor = favor; } public Map<String, Object> getCard() { return card; } public void setCard(Map<String, Object> card) { this.card = card; } public List<String> getFriends() { return friends; } public void setFriends(List<String> friends) { this.friends = friends; } public String getWork() { return work; } public void setWork(String work) { this.work = work; } public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", teacher=" + teacher + ", classes=" + Arrays.toString(classes) + ", favor=" + favor + ", card=" + card + ", friends=" + friends + ", work='" + work + '\'' + ", properties=" + properties + '}'; } } -
applicationContext.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 复杂set方法注入 --> <bean id="teacher" class="Teacher"> <property name="id" value="10"/> <property name="name" value="王老师"/> </bean> <bean id="student" class="Student"> <!--常量注入--> <property name="id" value="1"/> <property name="name" value="小李"/> <!--ref注入--> <property name="teacher" ref="teacher"/> <!--数组注入--> <property name="classes"> <array> <value>英语</value> <value>数学</value> <value>语文</value> </array> </property> <!--set注入--> <property name="favor"> <set> <value>羽毛球</value> <value>游泳</value> <value>滑雪</value> </set> </property> <!--Map注入--> <property name="card"> <map> <entry key="手机号" value="17828732"/> <entry key="学生号" value="2018232483237"/> </map> </property> <!--list注入--> <property name="friends"> <list> <value>小王</value> <value>小花</value> <value>小刘</value> </list> </property> <!--null值注入--> <property name="work"> <null></null> </property> <!--Properties注入--> <property name="properties"> <props> <prop key="username">root</prop> <prop key="password">12345</prop> </props> </property> </bean> </beans> -
测试
import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestDI { @Test public void testDI04(){ //复杂set方法注入 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = context.getBean("student", Student.class); System.out.println(student); /* Student{ id=1, name='小李', teacher=Teacher{id=10, name='王老师'}, classes=[英语, 数学, 语文], favor=[羽毛球, 游泳, 滑雪], card={手机号=17828732, 学生号=2018232483237}, friends=[小王, 小花, 小刘], work='null', properties={password=12345, username=root} } */ } }
3.3 拓展方法注入
3.3.1 c命名空间注入
在使用c命名空间注入时,需要在xml文件的头文件中导入约束
xmlns:c="http://www.springframework.org/schema/c"
使用c命名空间注入属性:
<?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:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--c命名空间注入-->
<bean id="userNew" class="User" c:id="10" c:name="小吴"/>
</beans>
3.3.2 p命名空间注入
在使用p命名空间注入时,需要在xml文件的头文件中导入约束
xmlns:p="http://www.springframework.org/schema/p"
使用c命名空间注入属性:
<?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:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空间注入-->
<bean id="userNew1" class="User" p:id="20" name="小武"/>
</beans>
4.Bean对象的自动装配
- 自动装配是使用Spring满足bean依赖的一种方式
- Spring会自动的在上下文中对某一个bean进行寻找其依赖的bean对象
4.1 Spring的bean的装配机制
- 在xml中显示的进行配置
- 在java中显示的配置
- 隐式的bean发现机制和自动装配
4.2 在XML中进行显示装配
- Byname与ByType
Teacher类
package com.xiaoli.dao;
public class Teacher {
private String name;
private int age;
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Student类
package com.xiaoli.dao;
public class Student {
private String name;
private int age;
private Teacher teacher;
public Student() {
}
public Student(String name, int age, Teacher teacher) {
this.name = name;
this.age = age;
this.teacher = teacher;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", teacher=" + teacher +
'}';
}
}
beans.xml配置文件
- ByName
<?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:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--xml进行显示的装配-->
<bean id="teacher" class="com.xiaoli.dao.Teacher">
<property name="name" value="王老师"/>
<property name="age" value="20"/>
</bean>
<!--自动装配:byName-->
<bean id="student" class="com.xiaoli.dao.Student" autowire="byName">
<property name="age" value="10"/>
<property name="name" value="小张"/>
</bean>
</beans>
-
ByType
<?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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--xml进行显示的装配--> <bean id="teacher" class="com.xiaoli.dao.Teacher"> <property name="name" value="王老师"/> <property name="age" value="20"/> </bean> <!--自动装配:byType--> <bean id="student" class="com.xiaoli.dao.Student" autowire="byType"> <property name="age" value="10"/> <property name="name" value="小张"/> </bean> </beans>
测试:
import com.xiaoli.dao.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testAutowire {
@Test
public void testAutowire(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = context.getBean("student", Student.class);
System.out.println(student);
}
}
测试结果

使用xml进行自动装配时,使用byName或者byType,可能会有多个类型或者名字一样的bean,就会出现装配失败的情况!!!
4.3 使用注解进行自动装配
Jdk1.5开始支持注解,Spring2.5开始全面支持注解。
备注:
@Autowired(required = false):表示对象可以为null;
@Autowired(required = true):表示对象可以不能为null;
-
准备工作,在Spring配置文件中引入context文件头
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> </beans> -
在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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--开启注解支持--> <context:annotation-config/> <!--开启组件扫描机制--> <context:component-scan base-package="com.xiaoli.dao"/> </beans> -
使用@Autowired注解,需要导入spring-aop依赖
<dependency> <groupId>spring</groupId> <artifactId>spring-aop</artifactId> <version>1.0.2</version> </dependency> -
@Autowired注解时按类型自动转型的,不支持id匹配
-
将bean注册到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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--开启注解支持--> <context:annotation-config/> <!--开启组件扫描机制--> <context:component-scan base-package="com.xiaoli.dao"/> <!--注册bean--> <bean id="teacher" class="com.xiaoli.dao.Teacher"> <property name="name" value="万老师"/> <property name="age" value="30"/> </bean> <bean id="student" class="com.xiaoli.dao.Student"/> </beans> -
Student类
package com.xiaoli.dao; import org.springframework.beans.factory.annotation.Autowired; public class Student { private String name; private int age; //在外部类的属性或者set方法上加上自动装配注解 @Autowired private Teacher teacher; public Student() { } public Student(String name, int age, Teacher teacher) { this.name = name; this.age = age; this.teacher = teacher; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", teacher=" + teacher + '}'; } } -
测试结果

-
-
@Autowired
在之前我们使用@Autowired自动装配注解,接下来我们使用与@Autowired搭配是的注解@Autowired,可以指定需要注入的值。
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--开启注解支持--> <context:annotation-config/> <!--开启组件扫描机制--> <context:component-scan base-package="com.xiaoli.dao"/> <!--注册bean--> <bean id="teacher1" class="com.xiaoli.dao.Teacher"> <property name="age" value="40"/> <property name="name" value="吴老师"/> </bean> <bean id="teacher2" class="com.xiaoli.dao.Teacher"> <property name="age" value="50"/> <property name="name" value="张老师"/> </bean> <bean id="student" class="com.xiaoli.dao.Student"/> </beans>Student类
package com.xiaoli.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; public class Student { private String name; private int age; //在外部类的属性或者set方法上加上自动装配注解 @Autowired @Qualifier(value = "teacher2") private Teacher teacher; public Student() { } public Student(String name, int age, Teacher teacher) { this.name = name; this.age = age; this.teacher = teacher; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", teacher=" + teacher + '}'; } }测试结果

5.使用注解进行开发
5.1 准备工作
在Spring4之后,如果想要使用注解进行开发,需要导入aop的依赖包
<dependency>
<groupId>spring</groupId>
<artifactId>spring-aop</artifactId>
<version>1.0.2</version>
</dependency>
在导入包之后,还需要在spring配置文件中引入一个context约束条件
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解支持-->
<context:annotation-config/>
</beans>
5.2 Bean的实现
在之前,我们都是通过xml文件进行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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解支持-->
<context:annotation-config/>
<!--开启组件扫描机制,扫描需要配置注解的包-->
<context:component-scan base-package="com.xiaoli.dao"/>
</beans>
2.在指定扫描包下进行配置注解
Student类
package com.xiaoli.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/*
Component组件在Spring容器中注册Bean
相当于:<bean id="stduent" class="com.xiaoli.dao.Student"/>
在不写value值时,默认为该类的全小写
*/
@Component("student")
public class Student {
/*
Value注解可以添加到属性上,也可以添加到set方法上
等价于:<property name="name" value="小李"/>
对属性进行注入
*/
@Value("小李")
private String name;
@Value("10")
private int age;
//这里对注解使用@Value会报错,使用自动装配,填入teacher类对bean的id
@Autowired
@Qualifier(value = "teacher")
private Teacher teacher;
public Student() {
}
public Student(String name, int age, Teacher teacher) {
this.name = name;
this.age = age;
this.teacher = teacher;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", teacher=" + teacher +
'}';
}
}
Teacher类
package com.xiaoli.dao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component(value = "teacher")
public class Teacher {
@Value("王老师")
private String name;
@Value("39")
private int age;
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试:

5.3 衍生注解
我们是使用注解,就是替代了我们在Spring容器(xml配置文件)中的配置步骤而已!只是使用注解方式进行开发会使得开发更加的快捷键与方便!!!我们接下来会介绍几个在开发中常用的注解:
@Component注解的三个衍生注解(@Component注解用于pojo层)
为了更好的进行开发分层,Spring可以使用其他三个注解,这三个注解与@Component注解是一样的功能,只是为了更好的进行分层,我们引入其他三个注解!!!
- @Controller注解:用于Web层
- @Service注解:用于Service层
- Repository注解:用于dao层
在开发中使用以上注解,相当于将这些类交予Spring容器进行统一管理!!!
5.4 作用域@Scope
在外面将Bean对象托管到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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/context/spring-context.xsd">
<!--
scope:默认是singleton(单例,相当于在内存中只有一份这个对象)
scope作用域的其他属性:
prototype:当一个bean当作用域被声明为prototype(原型模式)时候,表示一个bean对应多个对象实例。
request:当一个bean被声明为request时,表示在一次HTTP请求中,一个ben定义对应一个实例;即每个HTTP
请求都会有各自都bean实例。该作用域仅在基于web都Spring ApplicationContext情形下有效。
session:当一个作用域为Session,表示在一个HTTP Session中,一个bean定义一个实例。该作用域仅在基于Web
当Spring ApplicationContext下有效。
-->
<bean id="user" class="com.xiaoli.dao.User" scope="singleton">
</bean>
</beans>
5.5 注解开发与基于xml开发小结
-
XML与注解比较
-
xml可以适用于任何场景,结构清晰,维护方便
-
注解不是自己提供的类的情况下会出现无法使用的情况,但是开发简单,方便
-
-
XML与注解整合开发:推荐最佳实战
-
xml管理bean
-
注解完成属性注入
-
使用过程中,可以不使用扫描,扫描是为了类上的注解
<!--开启注解支持--> <context:annotation-config/>
-
-
作用:
- 使用注解驱动注册,从而使得注解生效
- 用于激活那些已经在spring容器中注册过的bean上面的注解,也就是显示的向Spring进行注册
- 如果不扫描包,则需要手动配置bean(将bean对象托管到Spring容器中)
- 如果不加注解驱动,则注入到值为null
6.基于Java类进行配置
在完全摒弃Spring xml配置文件下,如何进行开发呢?
我们使用JavaConfig,JavaConfig原来是Spring到一个子项目,他通过Java类的方式提供bean的定义信息,在Spring4的版本中,JavaConfig已经正式成为Spring4的核心功能!!!
6.1 存粹基于Java的代码
-
编写一个实体类(如Book)
Book实体类
package com.xiaoli.dao; import org.springframework.stereotype.Component; @Component(value = "book") public class Book { private String name; private String author; private float price; public Book() { } public Book(String name, String author, float price) { this.name = name; this.author = author; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } @Override public String toString() { return "Book{" + "name='" + name + '\'' + ", author='" + author + '\'' + ", price=" + price + '}'; } } -
新建一个config类,编写我们需要配置bean的配置类
BookConfig配置类
package com.xiaoli.dao; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; //@Configuration注解代表这是一个配置类 @Configuration public class BookConfig { //通过方法注册一个bean,这里的返回值就是bean的类型,方法名就是bean的id,方法名必须与id一致,否则会报错 @Bean public Book book(){ return new Book("西游记","吴承恩", (float) 80.8); } } -
测试代码
import com.xiaoli.dao.Book; import com.xiaoli.dao.BookConfig; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class TestAnnotationConfig { //测试存粹的注解开发,不使用xml配置文件 @Test public void test(){ //我们这里需要的Spring上下文是来自与注解配置类的实例 ApplicationContext context = new AnnotationConfigApplicationContext(BookConfig.class); Book book = context.getBean("book", Book.class); System.out.println(book); } }
6.2 使用场合
我们通过上面的代码,已经发现了基于存粹的Java代码编写Bean和注入bean成为可能,我们在之后学习Spring Boot与Spring Cloud框架的学习中,将会看到大量的这样的基于存粹的注解开发的代码!!!
浙公网安备 33010602011771号