Java开发中Spring IOC容器的使用详解
详解Spring IOC
文章目录
文章内容输出来源:
拉勾教育Java高薪训练营
看前如果没有基础的话建议先看上一篇手动实现IOC和AOP思路
Spring IoC基础
Spring IoC有两个重要的概念:
-
beans.xml
:定义实例化对象的类全限定类名以及类之间依赖关系的描述。 -
BeanFactory
:IOC容器,通过反射技术来实例化对象并维护对象之间的依赖关系。
1.BeanFactory与ApplicationContext区别
BeanFactory是Spring框架中IoC容器的顶层接口,它只是用来定义一些基础功能,定义一些基础规范,而 ApplicationContext是它的一个子接口,所以ApplicationContext是具备BeanFactory提供的全部功能的。
通常,我们称BeanFactory为SpringIOC的基础容器,ApplicationContext是容器的高级接口,比 BeanFactory要拥有更多的功能,比如说国际化支持和资源访问(xml,java配置类)等等
启动IoC容器的方式
-
Java环境下启动IoC容器
- ClassPathXmlApplicationContext:从类的根路径下加载配置文件(推荐使用)
- FileSystemXmlApplicationContext:从磁盘路径上加载配置文件
- AnnotationConfigApplicationContext:纯注解模式下启动Spring容器
-
Web环境下启动IoC容器 从xml启动容器
- 从xml启动容器
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <!--配置Spring ioc容器的配置文件--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!--使用监听器启动Spring的IOC容器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
- 从配置类启动容器
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <!--告诉ContextloaderListener知道我们使用注解的方式启动ioc容器--> <context-param> <param-name>contextClass</param-name> <param- value>org.springframework.web.context.support.AnnotationConfigWebAppli cationContext</param-value> </context-param> <!--配置启动类的全限定类名--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>com.lagou.edu.SpringConfig</param-value> </context-param> <!--使用监听器启动Spring的IOC容器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
2. 纯xml模式
2.1 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">
2.2 实例化Bean的三种方式
- 方式一:使用无参构造
在默认情况下,它会通过反射调用无参构造函数来创建对象。如果类中没有无参构造函数,将创建失败。
<!--配置service对象--> <bean id="userService" class="com.lagou.service.impl.TransferServiceImpl"> </bean>
- 方法二:使用静态方法构建
//Java代码实例 public class BeanFactory{ private static UserService userService; public static UserService getTransferService(){ return userService; } }
<!--使用静态方法创建对象的配置方式--> <bean id="userService" class="com.lagou.factory.BeanFactory" factory-method="getTransferService"></bean>
- 方法三:使用实例化方法构建
//Java代码实例 public class BeanFactory{ private UserService userService; public UserService getTransferService(){ return userService; } }
<!--使用实例方法创建对象的配置方式--> <bean id="beanFactory" class="com.lagou.factory.instancemethod.BeanFactory"></bean> <bean id="transferService" factory-bean="beanFactory" factory-method="getTransferService"></bean>
2.3 Bean的作用范围及生命周期
- 作用范围
在spring框架管理Bean对象的创建时,Bean对象默认都是单例的,但是它支持配置的方式改变作用范围。
作用范围官方提供的说明如下图:
在上图中提供的这些选项中,我们实际开发中用到最多的作用范围就是**singleton(单例模式)和 prototype(**原型模式,也叫多例模式)。
配置方式参考下面的代码:
<!--scope属性就是描述作用范围--> <bean id="transferService" class="com.lagou.service.impl.TransferServiceImpl" scope="singleton"> </bean>
-
生命周期
-
单例模式:singleton
单例模式的bean对象生命周期与容器相同。
-
多例模式:prototype
多例模式的bean对象,spring框架只负责创建,不负责销毁。
-
2.4 Bean标签属性
在基于xml的IoC配置中,bean标签是最基础的标签。它表示了IoC容器中的一个对象。换句话 说,如果一个对象想让spring管理,在XML的配置中都需要使用此标签配置,Bean标签的属性如下:
属性 | 效果 |
---|---|
id | 用于给bean提供一个唯一标识。在一个标签内部,标识必须唯一。 |
class | 用于指定创建Bean对象的全限定类名。 |
name | 用于给bean提供一个或多个名称。多个名称用空格分隔。 |
factory-bean | 用于指定创建当前bean对象的工厂bean的唯一标识。当指定了此属性之后, class属性失效。 |
factory-method | 用于指定创建当前bean对象的工厂方法,如配合factory-bean属性使用, 则class属性失效。如配合class属性使用,则方法必须是static的。 |
scope | 用于指定bean对象的作用范围。通常情况下就是singleton。当要用到多例模式时, 可以配置为prototype。 |
init-method | 用于指定bean对象的初始化方法,此方法会在bean对象装配后调用。必须是 一个无参方法。 |
destory-method | 用于指定bean对象的销毁方法,此方法会在bean对象销毁前执行。它只 能为scope是singleton时起作用。 |
2.5 DI 依赖注入的xml配置
-
依赖注入分类
-
按照注入的方式分类
-
构造函数注入:顾名思义,就是利用带参构造函数实现对类成员的数据赋值。
// 使用要求是,类中提供的构造函数参数个数必须和配置的参数个数一致,且数据类型匹配。同时需要注意的是,当没有无参构造时,则必须提供构造函数参数的注入,否则Spring框架会报错。 public class JdbcAccountDaoImpl implements AccountDao{ private ConnectionUtils connectionUtils; private String name; private int sex; private float money; public JdbcAccountDaoImpl(ConnectionUtils connectionUtils, String name, int sex, float money){ this.connectionUtils = connectionUtils; this.name = name; this.sex = sex; this.money = money; } } //xml name:用于给构造函数中指定名称的参数赋值。index:用于给构造函数中指定索引位置的参数赋值。 // value:用于指定基本类型或者String类型的数据。ref:用于指定其他Bean类型的数据。写的是其他bean的唯一标识。 <bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcAccountDaoImpl"> <constructor-arg name="connectionUtils" ref="connectionUtils"/> <constructor-arg name="name" value="zhangsan"/> <constructor-arg name="sex" value="1"/> <constructor-arg name="money" value="100.6"/> </bean>
-
set方法注入:它是通过类成员的set方法实现数据的注入。(使用最多的)
//利用字段的set方法实现赋值的注入方式。此种方式在实际开发中是使用最多的注 入方式。 public class JdbcAccountDaoImpl implements AccountDao{ private ConnectionUtils connectionUtils; private String name; private int sex; private float money; public void setConnectionUtils(ConnectionUtils connectionUtils){ this.ConnectionUtils = connectionUtils; } public void setName(String name){ this.name = name; } ... } <bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcAccountDaoImpl"> <property name="connectionUtils" ref="connectionUtils"/> <property name="name" value="zhangsan"/> <property name="sex" value="1"/> <property name="money" value="100.6"/> </bean>
-
-
按照注入的数据类型分类
- 基本类型和String:name-value
- 其他Bean类型:name-ref
- 复杂类型(集合类型)
<!--set注入复杂数据类型--> <property name="myArray"> <array> <value>array1</value> <value>array2</value> <value>array3</value> </array> </property> <property name="myMap"> <map> <entry key="key1" value="value1"/> <entry key="key2" value="value2"/> <entry key="key3" value="value3"/> </map> </property> <property name="mySet"> <set> <value>set1</value> <value>set2</value> <value>set3</value> </set> </property> <property name="myProperties"> <props> <prop>prop1</prop> <prop>prop2</prop> <prop>prop3</prop> </props> </property>
在相同结构的集合数据注入时,内部标签是通用的,例如array , list , set 这三个标签通用。
-
3. xml与注解相结合模式
1)实际企业开发中,纯xml模式使用已经很少了
2)引入注解功能,不需要引入额外的jar
3)xml+注解结合模式,xml文件依然存在,所以,spring IOC容器的启动仍然从加载xml开始
4)哪些bean的定义写在xml中,哪些bean的定义使用注解
-
第三方jar中的bean定义在xml,比如德鲁伊数据库连接池
-
自己开发的bean定义使用注解
3.1 xml中标签与注解的对应(IoC)
xml形式 | 对应的注解形式 |
---|---|
标签 | @Component(“accountDao”),注解加在类上 bean的id属性内容直接配置在注解后面如果不配置,默认定义个这个bean的id为类 的类名首字母小写; 另外,针对分层代码开发提供了@Componenet的三种别名@Controller、 @Service、@Repository分别用于控制层类、服务层类、dao层类的bean定义,这 四个注解的用法完全一样,只是为了更清晰的区分而已 |
标签的 scope属性 | @Scope(“prototype”),默认单例,注解加在类上 |
标签的init- method 属性 | @PostConstruct,注解加在方法上,该方法就是初始化后调用的方法 |
标签的destory- method 属性 | @PreDestory,注解加在方法上,该方法就是销毁前调用的方法 |
3.2 DI 依赖注入到的注解实现方式
- @Autowired(推荐使用)
public class TransferServiceImpl { @Autowired private AccountDao accountDao; } public class TransferServiceImpl { @Autowired @Qualifier(name="jdbcAccountDaoImpl") private AccountDao accountDao; }
如上第一个代码所示,这样装配回去spring容器中找到类型为AccountDao的类,然后将其注入进来。
这样会产生一个问题,当一个类型有多个bean值的时候,会造成无法选择具体注入哪一个的情况, 这个时候我们需要配合着@Qualifier使用。
@Qualifier告诉Spring具体去装配哪个对象。
- @Resource
@Resource 在 Jdk 11中已经移除,如果要使用,需要单独引入jar包。
且不常用,有需要的可以自行了解。
<dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency>
4. 纯注解模式
改造为纯注解模式,将xml中遗留的内容全部以注解的形式迁移出去,最终删除xml,从Java配置类启动对应注解
//xml中遗留的内容,目的就是将其全部以注解的形式迁移出去,最终删除xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" 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
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd "> <!--开启注解扫描,base-package指定扫描的包路径--> <context:component-scan base-package="com.lagou.edu"/> <!--引入外部资源文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--第三方jar中的bean定义在xml中--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> </beans>
@Configuration 注解,表名当前类是一个配置类
@ComponentScan 注解,替代 context:component-scan
@PropertySource,引入外部属性配置文件
@Import 引入其他配置类
@Value 对变量赋值,可以直接赋值,也可以使用 ${} 读取资源配置文件中的信息 @Bean 将方法返回对象加入 SpringIOC 容器
@Configuration @ComponentScan({"com.lagou.edu"}) @PropertySource({"classpath:jdbc.properties"}) /*@Import()*/ public class SpringConfig { @Value("${jdbc.driver}") private String driverClassName; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean("dataSource") public DataSource createDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName(driverClassName); druidDataSource.setUrl(url); druidDataSource.setUsername(username); druidDataSource.setPassword(password); return druidDataSource; } }
这样,我们就成功将xml中的内容全部用注解的形式迁移出去了。
本文地址:https://blog.csdn.net/weixin_43871142/article/details/108248877
下一篇: Java环境 Jmeter环境变量配置