spring IOC (Inversion of Control,控制反转)
从这一小节开始,我们进入spring的学习
在学习之前我把之前所有的代码都共享出来,方便大家学习 探讨。
代码地址:
https://gitee.com/cgyspace/code-demos
选用的spring版本: 5.2.13.RELEASE
依赖注入
构造器注入
<?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">
<bean id="userService" class="com.cgy.spring5.ioc.service.UserService">
<constructor-arg ref="userDao"/>
</bean>
<bean id="userDao" class="com.cgy.spring5.ioc.dao.UserDao">
</bean>
</beans>
package com.cgy.spring5.ioc.service;
import com.cgy.spring5.ioc.dao.UserDao;
import com.cgy.spring5.ioc.entity.User;
public class UserService {
private UserDao userDao;
public UserService() {
}
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public User getUser() {
return userDao.getUserByName("张三");
}
}
说明: 在利用构造器注入的时候,我习惯再加一个无惨构造器。因为有参构造器会覆盖无参构造器,在很多场景下,无参构造器会被框架所调用,如果没有的话会导致程序报错。
测试类
package com.cgy.spring5.ioc;
import com.alibaba.fastjson.JSON;
import com.cgy.spring5.ioc.entity.User;
import com.cgy.spring5.ioc.service.ClientService;
import com.cgy.spring5.ioc.service.LoginService;
import com.cgy.spring5.ioc.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
UserService bean = context.getBean(UserService.class);
System.out.println(JSON.toJSONString(bean.getUser()));
}
}
执行结果:
多参构造器
指定参数类型
<?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">
<bean name="user" class="com.cgy.spring5.ioc.entity.User">
<constructor-arg type="java.lang.String" value="张三"/>
<constructor-arg type="int" value="16"/>
<constructor-arg type="java.lang.String" value="123456"/>
</bean>
</beans>
指定参数索引
<?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会把所有的value值当做String 来处理 -->
<bean name="user" class="com.cgy.spring5.ioc.entity.User">
<constructor-arg index="0" value="张三"/>
<constructor-arg index="1" value="16"/>
</bean>
</beans>
setter方法注入
<?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">
<bean id="user" class="com.cgy.spring5.ioc.entity.User"/>
<bean name="userDao" class="com.cgy.spring5.ioc.dao.UserDao"/>
<bean name="userService" class="com.cgy.spring5.ioc.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
</beans>
package com.cgy.spring5.ioc.service;
import com.cgy.spring5.ioc.dao.UserDao;
import com.cgy.spring5.ioc.entity.User;
public class UserService {
private UserDao userDao;
public UserService() {
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public User getUser(){
return userDao.getUserByName("张三");
}
}
注入Collections
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">[emailprotected]</prop>
<prop key="support">[emailprotected]</prop>
<prop key="development">[emailprotected]</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
注入null值
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</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">
<bean name="userService" class="com.cgy.spring5.ioc.service.UserService" lazy-init="true"/>
</beans>
自动装配
Mode | Explanation |
---|---|
no | (默认)无自动装配。 Bean 引用必须由ref 元素定义。对于大型部署,建议不要更改默认设置,因为明确指定协作者可以提供更好的控制和清晰度。在某种程度上,它记录了系统的结构。 |
byName | 按属性名称自动装配。 Spring 寻找与需要自动装配的属性同名的 bean。例如,如果一个 bean 定义被设置为按名称自动装配,并且包含一个master 属性(即,它具有setMaster(..) 方法),那么 Spring 将查找一个名为master 的 bean 定义并使用它来设置属性。 |
byType | 如果容器中恰好存在一个该属性类型的 bean,则使该属性自动装配。如果存在多个错误,则会引发致命异常,这表明您可能不对该 bean 使用byType 自动装配。如果没有匹配的 bean,则什么也不会发生(未设置该属性)。 |
constructor | 类似于byType ,但适用于构造函数参数。如果容器中不存在构造函数参数类型的一个 bean,则将引发致命错误。 |
bean的作用范围
Scope | Description |
---|---|
singleton | (默认)将每个 Spring IoC 容器的单个 bean 定义范围限定为单个对象实例。 |
prototype | 将单个 bean 定义的作用域限定为任意数量的对象实例。 |
request | 将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有一个在单个 bean 定义后面创建的 bean 实例。仅在可感知网络的 Spring ApplicationContext 中有效。 |
session | 将单个 bean 定义的范围限定为 HTTP Session 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
application | 将单个 bean 定义的范围限定为ServletContext 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
websocket | 将单个 bean 定义的范围限定为WebSocket 的生命周期。仅在可感知网络的 Spring ApplicationContext 上下文中有效。 |
说明
request session application websocket 作用域只在web环境中有效
如果你使用的是springmvc的DispatcherServlet,则不用做任何处理,DispatcherServlet已经自己处理了这些作用域的底层实现
如果你用的是非springmvc的web技术 比如jsf 或者Struts,这时需要增加配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" >
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
</web-app>
如果你用的是 Servlet 3.0以上环境,则可以用WebApplicationInitializer 进行编程完成监听器的注册
另外,如果你的环境配置listener有问题,无法注册监听器你还可以使用过滤器完成此功能
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" >
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
DispatcherServlet
,RequestContextListener
和RequestContextFilter
都做完全相同的事情,即将 HTTP 请求对象绑定到正在为该请求提供服务的Thread
上。这使得在请求链和会话范围内的 Bean 可以在调用链的更下游使用。