首先来搭建下Spring的环境
添加 Spring 框架的依赖坐标
可以去Maven仓库查找:https://mvnrepository.com/
<!-- 添加Spring框架的核⼼依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
编写 Bean 对象
public class UserService {
public void test(){
System.out.println("Hello Spring!");
}
}
在 src\main\resources ⽬录下新建 spring.xml ⽂件,并拷⻉官⽹⽂档提供的模板内容到 xml 中。
配置 bean 到 xml 中,把对应 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/beans/spring-beans.xsd">
<!--
xmlns 即 xml namespace xml使⽤的命名空间
xmlns:xsi 即xml schema instance xml 遵守的具体规范
xsi:schemaLocation 本⽂档xml遵守的规范 官⽅指定
-->
<bean id="userService" class="com.xxxx.service.UserService"></bean>
<!--
id:bean对象的id,唯⼀标识。⼀般是Bean对象的名称的⾸字⺟⼩写
class:bean对象的类路径
-->
</beans>
最后加载配置⽂件,获取实例化对象
import com.xxxx.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
// 获取Spring上下⽂环境 (加载配置⽂件) , 生成管理相应的Bean对象
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
// 通过getBean⽅法得到Spring容器中实例化好的Bean对象 (实例化Bean对象)
// userService代表的是配置⽂件中bean标签的id属性值
//getBean : 参数即为spring配置文件中bean的id .
UserService userService = (UserService) ac.getBean("userService");
// 调⽤⽅法 (使⽤实例化对象)
userService.test();
}
}
这样我们的Spring的环境搭建就已经好了
Hello Spring!对象是谁创建的 ?
hello Spring!对象是由Spring创建的
Hello Spring!对象的属性是怎么设置的 ?
hello Spring!对象的属性是由Spring容器设置的
这个过程就叫控制反转 :
控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
依赖注入 : 就是利用set方法来进行注入的.
IOC是一种编程思想,由主动的编程变成被动的接收
IOC创建对象方式
注:通过默认构造器创建空构造⽅法必须存在否则创建失败
1、 通过无参构造方法来创建
User.java
public class User {
private String name;
public User() {
System.out.println("user无参构造方法");
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}
spring.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">
<!--
xmlns 即 xml namespace xml使⽤的命名空间
xmlns:xsi 即xml schema instance xml 遵守的具体规范
xsi:schemaLocation 本⽂档xml遵守的规范 官⽅指定
-->
<bean id="user" class="com.shsxt.pojo.User">
<property name="name" value="wang"/>
</bean>
</beans>
测试类
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//在执行getBean的时候, user已经创建好了 , 通过无参构造
User user = (User) context.getBean("user");
//调用对象的方法 .
user.show();
}
结果可以发现,在调用show方法之前,User对象已经通过无参构造初始化了!
2、 通过有参构造方法来创建
User.java
public class User {
private String name;
public User() {
System.out.println("user无参构造方法");
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+ name );
}
}
xml 有三种方式编写
<!-- 第一种根据index参数下标设置 -->
<bean id="user" class="com.shsxt.pojo.User">
<!-- index指构造方法 , 下标从0开始 -->
<constructor-arg index="0" value="wang"/>
</bean>
<!-- 第二种根据参数名字设置 -->
<bean id="user" class="com.shsxt.pojo.User">
<!-- name指参数名 -->
<constructor-arg name="name" value="wang"/>
</bean>
<!-- 第三种根据参数类型设置 -->
<bean id="user" class="com.shsxt.pojo.User">
<constructor-arg type="java.lang.String" value="wang"/>
</bean>
结论:
在配置文件加载的时候。其中管理的对象都已经初始化了。
Spring 配置⽂件加载
1、 根据相对路径加载资源
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
**2、**根据绝对路径加载资源
ApplicationContext ac = new FileSystemXmlApplicationContext("C:/IdeaWorkspace/spring01/src/main/resources/spring.xml");
3、 Spring 多配置⽂件加载
Spring 框架启动时可以加载多个配置⽂件到环境中。对于⽐较复杂的项⽬,可能对应的配置⽂件有多个,项⽬在启动部署时会将多个配置⽂件同时加载进来
spring.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="userService" class="com.xxxx.service.UserService"></bean>
</beans>
dao.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="userDao" class="com.xxxx.dao.UserDao"></bean>
</beans>
// 同时加载多个资源⽂件
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml","dao.xml");
4、 import其他配置⽂件
spring.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">
<!--导⼊需要包含的资源⽂件-->
<import resource="service.xml"/>
<import resource="dao.xml"/>
</beans
加载时只需加载总的配置⽂件即可
// 加载总的资源⽂件
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
Spring IOC 容器 Bean 对象实例化
1. 构造器实例化
2.静态⼯⼚实例化
当我们指定Spring使⽤静态⼯⼚⽅法来创建Bean实例时,Spring将先解析配置⽂件,并根据配置⽂件指定的信息,通过反射调⽤静态⼯⼚类的静态⼯⼚⽅法,并将该静态⼯⼚⽅法的返回值作为Bean实例,在这个过程中Spring不再负责创建Bean实例,Bean实例是由⽤户提供的静态⼯⼚⽅法提供的。
Spring三种实例化Bean的⽅式⽐较
⽅式⼀:通过bean的缺省构造函数创建,当各个bean的业务逻辑相互⽐较独⽴的时候或者和外界关联较少的时候可以使⽤。
⽅式二:利⽤静态factory⽅法创建,可以统⼀管理各个bean的创建,如各个bean在创建之前需要相同的初始化处理,则可⽤这个factory⽅法险进⾏统⼀的处理等等。
⽅式三:利⽤实例化factory⽅法创建,即将factory⽅法也作为了业务bean来控制,1、可⽤于集成其他框架的bean创建管理⽅法,2、能够使bean和factory的⻆⾊互换。
开发中项⽬⼀般使⽤⼀种⽅式实例化bean,项⽬开发基本采⽤第⼀种⽅式,交给Spring托管,使⽤时直接拿来使⽤即可。另外两种了解
Spring IOC 注⼊
依赖注入(Dependency Injection,DI)。
依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .
注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 .
Spring ⽀持的注⼊⽅式共有四种:set 注⼊、构造器注⼊、静态⼯⼚注⼊、实例化⼯⼚注⼊。
1、Set 注入 (重点)
要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is .
1、 属性字段提供set⽅法
UserService .java
public class UserService {
// 业务对象UserDao set注⼊(提供set⽅法)
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
2、 配置⽂件的bean标签设置property标签
<?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">
<!--
IOC通过property标签⼿动装配(注⼊):
Set⽅法注⼊
name:bean对象中属性字段的名称
ref:指定bean标签的id属性值
-->
<bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
<bean id="userService" class="com.xxxx.service.UserService">
<!--业务对象 注⼊-->
<property name="userDao" ref="userDao"/>
</bean>
</beans>
扩展:
常量注入:
<bean id="userService" class="com.xxxx.service.UserService">
<!-- 常⽤对象String 注⼊ -->
<property name="host" value="127.0.0.1"/>
<!-- 基本类型注⼊ -->
<property name="port" value="8080"/>
</bean>
Bean注入:
注意点:这里的值是一个引用,ref
<bean id="addr" class="com.xxxx.pojo.Address">
<property name="address" value="重庆"/>
</bean>
<bean id="student" class="com.xxxx.pojo.Student">
<property name="name" value="小明"/>
<property name="address" ref="addr"/>
</bean>
数组注入:
<bean id="student" class="com.xxxx.pojo.Student">
<property name="name" value="小明"/>
<property name="address" ref="addr"/>
<property name="books">
<array>
<value>西游记</value>
<value>红楼梦</value>
<value>水浒传</value>
</array>
</property>
</bean>
List注入:
<property name="hobbys">
<list>
<value>听歌</value>
<value>看电影</value>
<value>爬山</value>
</list>
</property>
Map注入:
<property name="card">
<map>
<entry key="中国邮政" value="456456456465456"/>
<entry key="建设" value="1456682255511"/>
</map>
</property>
set注入:
<property name="games">
<set>
<value>LOL</value>
<value>BOB</value>
<value>COC</value>
</set>
</property>
Null注入:
<property name="wife"><null/></property>
Properties注入:
<property name="info">
<props>
<prop key="学号">20190604</prop>
<prop key="性别">男</prop>
<prop key="姓名">小明</prop>
</props>
</property>
2、构造器注⼊
提供带参构造器
单个Bean对象作为参数
UserService .java
public class UserService {
private UserDao userDao; // JavaBean 对象
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public void test(){
System.out.println("UserService Test...");
userDao.test();
}
}
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">
<!--
IOC通过构造器注⼊:
通过constructor-arg标签进⾏注⼊
name:属性名称
ref:指定bean标签的id属性值
-->
<bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
<bean id="userService" class="com.xxxx.service.UserService">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
</beans>
多个Bean对象作为参数
UserService .java
public class UserService {
private UserDao userDao; // JavaBean 对象
private AccountDao accountDao // JavaBean 对象
public UserService(UserDao userDao, AccountDao accountDao) {
this.userDao = userDao;
this.accountDao = accountDao;
}
public void test(){
System.out.println("UserService Test...");
userDao.test();
accountDao.test();
}
}
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">
<!--
IOC通过构造器注⼊:
通过constructor-arg标签进⾏注⼊
name:属性名称
ref:指定bean标签的id属性值
-->
<bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
<bean id="accountDao" class="com.xxxx.dao.AccountDao" ></bean>
<bean id="userService" class="com.xxxx.service.UserService">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
<constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
</bean>
</beans>
Bean对象和常⽤对象作为参数
public class UserService {
private UserDao userDao; // JavaBean 对象
private AccountDao accountDao; // JavaBean 对象
private String uname; // 字符串类型
public UserService(UserDao userDao, AccountDao accountDao, String uname) {
this.userDao = userDao;
this.accountDao = accountDao;
this.uname = uname;
}
public void test(){
System.out.println("UserService Test...");
userDao.test();
accountDao.test();
System.out.println("uname:" + uname);
}
}
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">
<!--
IOC通过构造器注⼊:
通过constructor-arg标签进⾏注⼊
name:属性名称
ref:指定bean标签的id属性值
value:基本类型 常⽤对象的值
index:构造器中参数的下标,从0开始
-->
<bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
<bean id="accountDao" class="com.xxxx.dao.AccountDao" ></bean>
<bean id="userService" class="com.xxxx.service.UserService">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
<constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
<constructor-arg name="uname" value="admin"></constructor-arg>
</bean>
</beans>
构造器注入的循环依赖问题
多个bean对象中互相注⼊,则会出现循环依赖的问题。
解决方案: 将构造器注⼊改为set⽅法注⼊
Bean自动装配
- 自动装配是使用spring满足bean依赖的一种方法
- spring会在应用上下文中为某个bean寻找其依赖的bean
Spring中bean有三种装配机制,分别是:
- 在xml中显式配置;
- 在java中显式配置;
- 隐式的bean发现机制和自动装配
byName
autowire byName (按名称自动装配)
由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。
采用自动装配将避免这些错误,并且使配置简单化。
测试:
修改bean配置,增加一个属性 autowire=“byName”
<bean id="user" class="com.shsxt.pojo.User" autowire="byName">
<property name="str" value="wang"/>
</bean>
当一个bean节点带有 autowire byName的属性时。
- 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小 写的字符串,即cat。
- 去spring容器中寻找是否有此字符串名称id的对象
- 如果有,就取出注入;如果没有,就报空指针异常。
byType
autowire byType (按类型自动装配)
使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。
NoUniqueBeanDefinitionException
测试:
将user的bean配置修改一下 : autowire=“byType”
在注册一个cat 的bean对象!
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User" autowire="byType">
<property name="str" value="qinjiang"/>
</bean>
测试,报错:NoUniqueBeanDefinitionException
删掉cat2,将cat的bean名称改掉!测试!因为是按类型装配,所以并不会报异常,也不影响最后的结果。甚至将id属性去掉,也不影响结果。
使用注解
jdk1.5开始支持注解,spring2.5开始全面支持注解。
准备工作:利用注解的方式注入属性。
1、在spring配置文件中引入context文件头
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
2、开启属性注解支持!(开启扫描器)
<context:annotation-config/>
3、这样我们就可以使用注解了
总结一下注解:
@Autowired
- @Autowired是按类型自动转配的,不支持id匹配。
- 需要导入 spring-aop的包!
将User类中的set方法去掉,使用@Autowired注解
此时配置文件内容
<context:annotation-config/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User"/>
@Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。
//如果允许对象为null,设置required = false,默认为true
@Autowired(required = false)
private Cat cat;
@Qualifier
- @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
- @Qualifier不能单独使用。
配置文件修改内容,保证类型存在对象。且名字不为类的默认名字!
<bean id="dog1" class="com.kuang.pojo.Dog"/>
<bean id="dog2" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>
没有加Qualifier测试,直接报错
在属性上添加Qualifier注解
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;
这样就可以了
@Resource
- @Resource如有指定的name属性,先按该属性进行byName方式查找装配;
- 其次再进行默认的byName方式进行装配;
- 如果以上都不成功,则按byType的方式自动装配。
- 都不成功,则报异常
@Component
它是这些注解里面最普通的一个注解,一般用于把普通pojo实例化到spring容器中
@Controller
用于标注控制层,表示向控制层注入服务层的数据
@Service
用于标注服务层,来进行业务的逻辑处理,在服务层注入DAO层数据
@Repository
用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件
@ComponentScan
这个注解长得和@Component有点像,但是他们是完全两个不同类型的注解,@Component像一个标签,标志着你这类是个啥,而@ComponentScan像一个路标,告诉你去哪找东西
@ResponseBody
加了这个注解的类会将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML。 需要注意的是,在使用此注解之后的数据不会再走ViewResolver,而是直接将数据写入到输入流中,它的效果相当于用response对象输出指定格式的数据。
@RestController
@RestController = @Controller + @ResponseBody
写这一个注解就相当于写了后面的两个注解,在返回值是json串的非常方便,但同时也会有一个问题,加了这个注解就不能返回jsp或者html页面,这时可以通过返回视图数据的方式来返回页面
@RequestMapping(“xxxx”)
它用于 映射客户端的访问地址,可以被应用于类和方法上面,客户进行访问时,URL应该为类+方法上面的这个注解里面的内容。
@Autowired与@Resource异同
相同点:
@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。
区别
@Autowired:
1、是默认按照类型进行装配(属于spring),默认情况是要求依赖的对象必须存在,如果允许null值,则需要将required属性设置为false。如:@autowried(required=false)
2.如果需要按照名称装配需要用到另一个注解@qualifier(“name”)和@autowried组合使用
@Resource:
装配时会先根据名称进行装配,当找不到名称与之匹配的bean时才按照类型进行装配,如果写了name的属性则只会根据name的名称去装配
- 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
- 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
- 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出 异常
- 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配
注⼊⽅式的选择
开发项⽬中set⽅式注⼊----------⾸选
Spring中Bean 的生命周期
bean的生命周期可分为四个阶段:
bean的定义: 在配置文件中通过bean标签来声明
bean的初始化: 容器启动时,将bean对象实例化
两种方式:
1、通过在bean标签中设置init-method属性,设置值是对应的是需要的方法
2、bean对象实现的接口InitializingBean
bean的使用:
两种方式:
1、ApplicationContext ac = new ClassPathXmlApplicationContext(“spring.xml”);
ac.getBean(“”);
2、BeanFactory factory = new ClassPathXmlApplicationContext(“spring.xml”)
factory.getBean(“”)
bean的销毁:
1、通过bean标签中的destory-method的属性值指定销毁时执行的方法
2、Bean对象的方法
3、关闭IOC容器