IOC
IOC是inversion of Control的简写,译为"控制反转"。它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序。
控制反转是一种编程思想,将对象的创建权利和对象之间的关系的维护权交出去,由第三方容器负责。实现控制反转的思想是依赖注入(DI)
IOC 容器
Spring 通过IOC 容器 来管理所有Java 对象的实例化、初始化和组装的对象 ,Spring IoC 容器管理的对象称为bean。Bean初始化信息以及它们之间的依赖关系,反映在容器使用的配置元数据中(xml或者注解)。在容器内部,这些 bean 定义表示为 BeanDefinition 对象。
org.springframework.beans 和 org.springframework.context 包是 Spring Framework IoC 容器的基础
BeanFactory 接口提供了一种高级配置机制,能够管理任何类型的对象。ApplicationContext 是 BeanFactory 的子接口,增加了:
- 更轻松地与 Spring 的 AOP 特性集成
- 消息资源处理(用于国际化)
- 事件发布
- 应用程序层特定上下文,例如用于 Web 应用程序的
WebApplicationContext。
简而言之,BeanFactory 提供了配置框架和基本功能,而 ApplicationContext 增加了更多企业级功能。
org.springframework.context.ApplicationContext 接口代表 Spring IoC 容器,负责实例化、配置和组装 bean。容器通过读取配置元数据来获取有关要实例化、配置和组装的组件的指令。
配置元数据可以表示为带注解、java类、外部 XML 文件
ApplicationContext 接口的几个实现是核心 Spring 的一部分。在独立应用程序中,通常创建 AnnotationConfigApplicationContext 或 ClassPathXmlApplicationContext 的实例。
依赖注入
DI (Dependency Injection) : 依赖注入,依赖注入实现了控制反转的思想。指Spring创建对象的过程中,将对象依赖属性通过配置进行注入。依赖注入常见的实现方式包括两种:
-
第一种: set注入
-
第二种: 构造注入
Bean管理说的是: Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)
IOC的实现过程
Spring中的容器是通过map来实现的,具体是ConcurrentHashMap,默认大小是256,主要存储Bean的描述类
-
在
bean.xml加载后生产BeanDefinition对象,此对象为bean的描述对象. -
在
spring中,有BeanDefinitionReader一个接口,通过这个接口实现不同的类来加载bean.xml配置文件。
上面的例子就是通过
XmlBeanDefinitionReader类来加载bean.xml文件。javaprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } -
加载完成
bean.xml配置之后会创建BeanDefinition对象,然后通过BeanFactory工厂+反射来进行实例化的。BeanFactory接口下分别有三种接口:ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory,上述示例中是通过ListableBeanFactory工厂进行创建对象的。AbstractRefreshableApplicationContext.java内容:javaprotected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); //把创建bean对象,然后放入容器中. loadBeanDefinitions(beanFactory); this.beanFactory = beanFactory; } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }

基于xml管理Bean
xml配置
别名
和id一样,只是起另一个别名。同样可以获取cat类
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">
<bean id="cat" class="com.light.automatic_assembly.Cat">
<property name="name" value="哭哭啼啼的大脸猫" />
</bean>
<alias name="cat" alias="catNew" />
</beans>
bean
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">
<!--
id:唯一标识符
class:对象所对应该的全限定名 包名 + 类型
name: 也是别名
-->
<bean id="cat" class="com.light.automatic_assembly.Cat" name="cat1,cat2">
<property name="name" value="哭哭啼啼的大脸猫" />
</bean>
</beans>
import
跟导入文件一样,这里是导入配置文件
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">
<import resource="bean.xml" />
<import resource="bean2.xml" />
<import resource="bean3.xml" />
<!--
id:唯一标识符
class:对象所对应该的全限定名 包名 + 类型
name: 也是别名
-->
<bean id="cat" class="com.light.automatic_assembly.Cat" name="cat1,cat2">
<property name="name" value="哭哭啼啼的大脸猫" />
</bean>
</beans>
获取Bean
java
public class TestPerson {
public void testAdd(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取bean
Person person = (Person) context.getBean("person");
person.add();
//根据类型获取bean
Person bean = context.getBean(Person.class);
bean.add();
//根据id和类型获取bean
Person bean1 = context.getBean("person", Person.class);
bean1.add();
}
}
当根据类型获取bean时,要求配置文件中指定类型的bean有且只能有一个。如果有多个会抛出异常:org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.light.www.Person' available: expected single matching bean but found 2: person,person1
expected single matching bean but found 2: person,person1 这句翻译为期望匹配一个单实例的bean, 但是发现了两个:person,person1。
组件类实现接口,获取对象
UserDao.java
java
public interface UserDao {
public void run();
}
配置bean: <bean id="UserDaoImpl" class="com.light.www.UserDaoImpl"/>
UserDaoImpl.java
java
public class UserDaoImpl implements UserDao {
@Override
public void run() {
System.out.println("run...");
}
}
-
如果组件类实现了接口,根据接口类型可以获取 bean 吗?
可以,前提是bean唯一
-
如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?
不行,因为bean不唯一
依赖注入
book类
java
package com.light.di;
public class Book {
private String name;
private String author;
private String other;
private String xml;
private String cdata;
public Book() {
System.out.println("使用setter注入,首先创建无惨对象,然后调用Setter方法");
}
public Book(String name, String author) {
System.out.println("使用构造器注入,直接使用构造方法注入");
this.name = name;
this.author = author;
}
public String getOther() {
return other;
}
public void setOther(String other) {
this.other = other;
}
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 String getXml() {
return xml;
}
public String getCdata() {
return cdata;
}
public void setCdata(String cdata) {
this.cdata = cdata;
}
public void setXml(String xml) {
this.xml = xml;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", other='" + other + '\'' +
", xml='" + xml + '\'' +
", cdata='" + cdata + '\'' +
'}';
}
}
基于Setter注入, xml配置:
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">
<bean id="book" class="com.light.di.Book">
<property name="name" value="java从入门到入坑" />
<property name="author" value="小毛驴" />
<!-- null值-->
<property name="other">
<null />
</property>
<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 解决方案一: 使用XML实体来代替 -->
<property name="xml" value="a < b" />
<!-- C[DATA]节-->
<property name="cdata">
<!-- 解决方案二:使用CDATAT -->
<!-- CDATA中的C代表character,是文本、字符的含义,CDATA就表示纯文本数据 -->
<!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
<!-- 所以CDATA节中写什么符号都随意 -->
<value><![CDATA[a < b]]></value>
</property>
</bean>
</beans>
基于构造器注入,xml配置:
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">
<bean id="bookCon" class="com.light.di.Book">
<constructor-arg name="name" value="c++从入门到秃头" />
<!-- constructor-arg的index表示构造器中参数的位置,必须对应,所以一般使用name比较好-->
<constructor-arg index="1" value="light" />
</bean>
</beans>
其他特殊值注入:
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">
<bean id="book" class="com.light.di.Book">
<!-- 字面量 -->
<property name="name" value="java从入门到入坑" />
<property name="author" value="小毛驴" />
<!-- null值-->
<property name="other">
<null />
</property>
<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 解决方案一: 使用XML实体来代替 -->
<property name="xml" value="a < b" />
<!-- C[DATA]节-->
<property name="cdata">
<!-- 解决方案二:使用CDATAT -->
<!-- CDATA中的C代表character,是文本、字符的含义,CDATA就表示纯文本数据 -->
<!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
<!-- 所以CDATA节中写什么符号都随意 -->
<value><![CDATA[a < b]]></value>
</property>
</bean>
</beans>
测试:
java
public class TestBook {
@Test
public void testSetter(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
//setter注入
Book bean = context.getBean("book", Book.class);
System.out.println(bean);
//构造器注入
Book bookCon = context.getBean("bookCon", Book.class);
System.out.println(bookCon);
}
}
对象、数组、集合类型注入
以部门和员工为例:
Employs.java 代码:
java
package com.light.di;
public class Employs {
private String name;
private Integer age;
private Dept dept;
private EmpInfo empInfo;
public Employs() {
}
public Employs(String name, Integer age, Dept dept) {
this.name = name;
this.age = age;
this.dept = dept;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public EmpInfo getEmpInfo() {
return empInfo;
}
public void setEmpInfo(EmpInfo empInfo) {
this.empInfo = empInfo;
}
@Override
public String toString() {
return "Employs{" +
"name='" + name + '\'' +
", age=" + age +
", dept=" + dept +
", empInfo=" + empInfo +
'}';
}
}
Dept.java
java
package com.light.di;
import java.util.List;
import java.util.Map;
public class Dept {
private String name;
private List<Employs> employs;
private Map<String, Leader> leaderMap;
public Dept() {
}
public Dept(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Map<String, Leader> getLeaderMap() {
return leaderMap;
}
public void setLeaderMap(Map<String, Leader> leaderMap) {
this.leaderMap = leaderMap;
}
public void setName(String name) {
this.name = name;
}
public List<Employs> getEmploys() {
return employs;
}
public void setEmploys(List<Employs> employs) {
this.employs = employs;
}
@Override
public String toString() {
return "Dept{" +
"name='" + name + '\'' +
", employs=" + employs +
", leaderMap=" + leaderMap +
'}';
}
}
empInfo.java
java
package com.light.di;
public class EmpInfo {
private String province;
private String city;
private String county;
private String detailAddr;
private String telephone;
private String Idcard;
public EmpInfo() {
}
public EmpInfo(String province, String city, String county, String detailAddr, String telephone, String idcard) {
this.province = province;
this.city = city;
this.county = county;
this.detailAddr = detailAddr;
this.telephone = telephone;
Idcard = idcard;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCounty() {
return county;
}
public void setCounty(String county) {
this.county = county;
}
public String getDetailAddr() {
return detailAddr;
}
public void setDetailAddr(String detailAddr) {
this.detailAddr = detailAddr;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getIdcard() {
return Idcard;
}
public void setIdcard(String idcard) {
Idcard = idcard;
}
@Override
public String toString() {
return "EmpInfo{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
", county='" + county + '\'' +
", detailAddr='" + detailAddr + '\'' +
", telephone='" + telephone + '\'' +
", Idcard='" + Idcard + '\'' +
'}';
}
}
leader.java
java
package com.light.di;
public class Leader {
private String name;
private String position;
public Leader() {
}
public Leader(String name, String position) {
this.name = name;
this.position = position;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
@Override
public String toString() {
return "Leader{" +
"name='" + name + '\'' +
", position='" + position + '\'' +
'}';
}
}
注入对象xml配置:
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">
<bean id="dept-safe" class="com.light.di.Dept">
<property name="name" value="安保部" />
</bean>
<bean id="employs" class="com.light.di.Employs">
<!--普通属性注入-->
<property name="name" value="lucy" />
<property name="age" value="30" />
<!--对象属性注入-->
<!--第一种方式 外部注入: ref="dept" ref表示引入id为dept的对象-->
<property name="dept" ref="dept-safe" />
<!-- 级联赋值 -->
<property name="dept.name" value="市场部" />
<!-- 第二种方式:内部注入 在property内部在定义个Bean标签-->
<property name="empInfo" >
<bean id="empInfo" class="com.light.di.EmpInfo">
<property name="city" value="xi an" />
<property name="county" value="xin cheng" />
<property name="province" value="shanxi" />
<property name="detailAddr" value="cheng bei 188 number." />
<property name="idcard" value="EM1002120"/>
<property name="telephone" value="18828250022" />
</bean>
</property>
<!--数组注入-->
<property name="hobby">
<array>
<value>吃饭</value>
<value>睡觉</value>
<value>敲代码</value>
</array>
</property>
</bean>
<!--员工-->
<bean id="employs-one" class="com.light.di.Employs">
<property name="name" value="tech-one" />
<property name="age" value="30" />
</bean>
<bean id="employs-two" class="com.light.di.Employs">
<property name="name" value="tech-two" />
<property name="age" value="20" />
</bean>
<!--领导-->
<bean id="leader-one" class="com.light.di.Leader">
<property name="name" value="张xx" />
<property name="position" value="技术总监" />
</bean>
<bean id="leader-two" class="com.light.di.Leader">
<property name="name" value="王大壮" />
<property name="position" value="项目经理" />
</bean>
<bean id="dept-tech" class="com.light.di.Dept">
<property name="name" value="技术部" />
<!--注入list集合-->
<property name="employs">
<list>
<!--如果list里面是普通的值,那么就可以使用value标签<value></value>-->
<!--我们这里list里面的对象,所以需要使用ref引入外部类-->
<ref bean="employs-one"/>
<ref bean="employs-two" />
</list>
</property>
<!--注入map集合-->
<!--<property name="leaderMap">
<map>
<entry>
<key>
<value>10020</value>
</key>
<value>
<ref bean="leader-one" />
</value>
</entry>
<entry>
<key>
<value>10021</value>
</key>
<value>
<ref bean="leader-two" />
</value>
</entry>
</map>
</property>-->
<property name="leaderMap">
<map>
<!--如果是普通的值 直接使用value属性-->
<entry key="10010" value-ref="leader-two" />
<entry key="10012" value-ref="leader-two" />
</map>
</property>
</bean>
</beans>
测试:
java
package com.light.di;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestBook {
@Test
public void testSetter(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
//setter注入
Book bean = context.getBean("book", Book.class);
System.out.println(bean);
//构造器注入
Book bookCon = context.getBean("bookCon", Book.class);
System.out.println(bookCon);
}
@Test
public void testEmploys(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di-employ.xml");
Employs bean = context.getBean(Employs.class);
System.out.println(bean);
}
@Test
public void testDept(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di-employ.xml");
Dept bean = context.getBean("dept-tech", Dept.class);
System.out.println(bean);
}
}
引入资源
factorys.java
java
package com.light.di;
import java.util.List;
import java.util.Map;
public class Factorys {
private String name;
private List<Employs> employsList;
private Map<String, Leader> leaderMap;
public Factorys() {
}
public Factorys(String name, List<Employs> employsList, Map<String, Leader> leaderMap) {
this.name = name;
this.employsList = employsList;
this.leaderMap = leaderMap;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Employs> getEmploysList() {
return employsList;
}
public void setEmploysList(List<Employs> employsList) {
this.employsList = employsList;
}
public Map<String, Leader> getLeaderMap() {
return leaderMap;
}
public void setLeaderMap(Map<String, Leader> leaderMap) {
this.leaderMap = leaderMap;
}
@Override
public String toString() {
return "Factorys{" +
"name='" + name + '\'' +
", employsList=" + employsList +
", leaderMap=" + leaderMap +
'}';
}
}
注入对象xml配置:
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"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--员工-->
<bean id="employs-one" class="com.light.di.Employs">
<property name="name" value="tech-one" />
<property name="age" value="30" />
</bean>
<bean id="employs-two" class="com.light.di.Employs">
<property name="name" value="tech-one" />
<property name="age" value="30" />
</bean>
<!--领导-->
<bean id="leader-one" class="com.light.di.Leader">
<property name="name" value="张xx" />
<property name="position" value="技术总监" />
</bean>
<bean id="leader-two" class="com.light.di.Leader">
<property name="name" value="王大壮" />
<property name="position" value="项目经理" />
</bean>
<!--引入资源-->
<util:map id="leaders-map">
<entry key="10010" value-ref="leader-one" />
<entry key="10011" value-ref="leader-two" />
</util:map>
<util:list id="emp-list">
<ref bean="employs-one" />
<ref bean="employs-two" />
</util:list>
<bean id="factorys" class="com.light.di.Factorys">
<!--注入属性-->
<property name="name" value="面包厂"/>
<property name="leaderMap" ref="leaders-map" />
<property name="employsList" ref="emp-list" />
</bean>
<!--p命名空间-->
<bean id="factorysp" class="com.light.di.Factorys" p:name="袜子厂" p:leaderMap-ref="leaders-map" p:employsList-ref="emp-list" />
<!--引入外部资源 构建mysql实例-->
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
<property name="driverClassName" value="${jdbc.driver}" />
</bean>
</beans>
jdbc.properties
properties
jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/book?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
测试
java
@Test
public void testFactorys(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean-import.xml");
//引入资源
Factorys foctorys = context.getBean("factorys", Factorys.class);
System.out.println(foctorys);
//引入p空间
Factorys foctorysp = context.getBean("factorysp", Factorys.class);
System.out.println(foctorysp);
//引入外部资源
DruidDataSource dataSource = context.getBean("druidDataSource", DruidDataSource.class);
System.out.println(dataSource.getUrl());
}
bean生命周期
作用域
在Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围,各取值含义参加下表:
| 作用域 | 描述 |
|---|---|
| singleton(单例) | (默认)为每个 Spring IoC 容器将单个 bean 定义限定为单个对象实例。内存中只有一个对象。 |
| prototype(原型) | 将单个 bean 定义限定为任意数量的对象实例。每次都会创建对象,内存中会存在多个对象 |
| request(请求) | 将单个 bean 定义限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有其自己的 bean 实例,该实例根据单个 bean 定义创建。仅在 web 感知 Spring ApplicationContext 的上下文中有效。 |
| session(会话) | 将单个 bean 定义限定为 HTTP Session 的生命周期。仅在 web 感知 Spring ApplicationContext 的上下文中有效。 |
| application | application(应用) |
| websocket | 将单个 bean 定义限定为 WebSocket 的生命周期。仅在 web 感知 Spring ApplicationContext 的上下文中有效。 |
单例模式示例图

prototype示例图

xml配置
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">
<bean id="factorys" class="com.light.di.Factorys" scope="singleton">
<!--注入属性-->
<property name="name" value="面包厂"/>
<property name="leaderMap" ref="leaders-map" />
<property name="employsList" ref="emp-list" />
</bean>
</beans>
生命周期
bean生命周期步骤:
- bean对象创建 (调用无参数构造)
- 给bean对象设置相关属性 (初始化之前)
- bean前置处理器 (调用初始化方法之前执行)
- bean对象初始化(调用指定初始化方法)
- bean后置处理器(初始化之后执行)
- bean对象创建完成了,可以使用了
- bean对象销毁(配置指定销毁的方法)
- lOC容器关闭了
BeanCycle类
java
public class BeanCycle {
private String name;
public BeanCycle() {
System.out.println("1.bean对象创建 (调用无参数构造)");
}
public void initMethods(){
System.out.println("4.bean对象初始化");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("2 给bean对象设置相关属性 (初始化之前)");
}
public void destroyedMethod(){
System.out.println("7.bean对象销毁(配置指定销毁的方法)");
}
@Override
public String toString() {
return "BeanCycle{" +
"name='" + name + '\'' +
'}';
}
}
MyBeanPost类
java
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3 bean前置处理器 (调用指定初始化方法之前执行)");
System.out.println(beanName + "::" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("5 bean后置处理器 (初始化之后)");
System.out.println(beanName + "::" + bean);
return bean;
}
}
xml配置
必须和BeanCycle类的bean的xml写在一起
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">
<bean id="bean-cycle" class="com.light.cycle.BeanCycle" init-method="initMethods" destroy-method="destroyedMethod">
<property name="name" value="测试数据"/>
</bean>
<bean id="my-bean-post" class="com.light.cycle.MyBeanPost"/>
</beans>
FactoryBean
FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObiect()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。
将来我们整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。
java:
java
public class FactoryBeanExp implements FactoryBean<Employs> {
@Override
public Employs getObject() throws Exception {
return new Employs();
}
@Override
public Class<?> getObjectType() {
return Employs.class;
}
}
xml配置:
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">
<bean id="factory-bean" class="com.light.cycle.FactoryBeanExp" />
</beans>
测试:
java
@Test
public void testFactoryBeanExp(){
ApplicationContext context = new ClassPathXmlApplicationContext("factory-bean.xml");
//引入资源
Employs employs = (Employs) context.getBean("factory-bean");
System.out.println(employs);
}
自动装配
根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值。本质还是通过setter方法进行注入
cat类
java
public class Cat {
private String name;
public Cat() {
}
public Cat(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
自动装配类:
java
public class AutomaticAssembly {
private Cat cat;
private Book book;
public AutomaticAssembly() {
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "AutomaticAssembly{" +
"cat=" + cat +
", book=" + book +
'}';
}
}
两种自动装配方式:
-
byType: 根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值若在
IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null若在
IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionExceptionxml<?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="cat" class="com.light.automatic_assembly.Cat"> <property name="name" value="大脸猫"/> </bean> <bean id="book" class="com.light.di.Book"/> <bean id="auto" class="com.light.automatic_assembly.AutomaticAssembly" autowire="byType"/> </beans> -
byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值. 所以属性名(AutomaticAssembly类中属性名cat和book)必须要和bean中的id(cat,book)一致。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"> <bean id="cat" class="com.light.automatic_assembly.Cat"> <property name="name" value="大脸猫"/> </bean> <bean id="book" class="com.light.di.Book"/> <bean id="auto" class="com.light.automatic_assembly.AutomaticAssembly" autowire="byName "/> </beans>
基于注解管理Bean
在基于XML的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"
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>
<context:annotation-config/> 元素隐式注册以下后处理器:
ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessorEventListenerMethodProcessor
这些PostProcessor是 Spring让 IOC 容器"看懂注解"的桥梁------容器本身只认识 BeanDefinition,每种注解都需要一个对应的处理器来解析生效。
| 后置处理器 | 处理的注解 | 作用 |
|---|---|---|
AutowiredAnnotationBeanPostProcessor |
@Autowired、@Value、@Inject |
在属性填充阶段对字段、setter 方法、任意配置方法执行依赖注入 |
CommonAnnotationBeanPostProcessor |
@Resource、@PostConstruct、@PreDestroy |
JSR-250 支持:资源注入 + 初始化/销毁生命周期回调 |
ConfigurationClassPostProcessor |
@Configuration、@Bean、@Import、@ComponentScan 等 |
解析 Java 配置类,把 @Bean 方法等转化为 BeanDefinition 注册进容器 |
PersistenceAnnotationBeanPostProcessor |
@PersistenceContext、@PersistenceUnit |
JPA 支持:注入 EntityManager 等持久化资源 |
EventListenerMethodProcessor |
@EventListener |
把标注了 @EventListener 的方法注册为应用事件监听器 |
注解
从Java5开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。
java
格式:@注解名称(属性1=值1...)
Spring从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 XML配置。
Spring 通过注解实现自动装配的步骤如下:
-
引入依赖
-
开启组件扫描
Spring默认不使用注解装配 Bean,因此我们需要在 Spring的 XML 配置中,通过 context:component-scan 元素开启 Spring Beans的自动扫描功能。开启此功能后,Spring 会自动从扫描指定的包(base-package 属性设置)及其子包下的所有类,如果类上使用了 @Component 注解,就将该类装配到容器中。
有三种方式开启:
-
全部扫描:某个包下都扫描
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:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/beans/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 要使用注解必须加上: 1.xmlns:context="http://www.springframework.org/schema/context" 2. xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/beans/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" --> <!--全部扫描--> <context:component-scan base-package="com.light.www" /> </beans> -
排除组件扫描:排除某些注解,其余都扫描
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:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/beans/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--排序组件扫描--> <context:component-scan base-package="com.light.www"> <!--context:exclude-filter标签:指定排除规则--> <!-- type:设置排除或包含的依据 type="annotation",根据注解排除,expression中设置要排除的注解的全类名 type="assignable",根据类型排除,expression中设置要排除的类型的全类名 --> <context:exclude-filter type="annotation" expression="com.light.www.controller"/> </context:component-scan> </beans> -
指定组件扫描:只扫描指定的注解
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:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/context http://www.springframework.org/schema/beans/spring-context.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--指定组件扫描--> <context:component-scan base-package="com.light.www"> <!--context:include-fi1ter标签:指定在原有扫描规则的基础上追加的规则--> <!-- use-default-fi1ters属性: 取值false表示关闲默认扫描规则--> <!-- 此时必须设置use-default-fi1ters="false",因为默认规则即扫描指定包下所有类 --> <!-- type:设置排除或包含的依据 type="annotation",根据注解指定,expression中设置要指定的注解的全类名 type="assignable",根据类型指定,expression中设置要指定的类型的全类名 --> <context:include-filter type="annotation" expression="com.light.www.controller"/> </beans>
-
-
使用注解定义 Bean
-
依赖注入
spring中常用的注解
| Spring | 作用 |
|---|---|
@Autowired |
自动装配注解 |
@Component |
加上此注解,会使类创建的对象加入到容器。 |
@Scope("singleton") |
作用域 |
@Qualifier |
制定具体的注入 |
@Value |
无等效项 |
java
//相当于<bean id="user" value="..."
//首字母小写
@Component(value = "user")
public class User {
}
Autowrited
单独使用@Autowired注解,默认根据类型装配。【默认是byType】
java
//表示此注解可以用到的地方:构造器、方法等
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* 该注解有一个required属性,默认值是true,表示在注入的时候要求被注入的Bean必须是存在的,如果不存在则报错。
* 如果required属性设置为false,表示注入的Bean存在或者不存在都没关系,存在的话就注入,不存在的话,也不报错。
*/
boolean required() default true;
}
属性注入:在属性上使用@Autowired注入
java
@Controller
public class UserController {
//@Autowired 让 Spring 容器自动把 UserServiceImpl 的 Bean 注入到 userService 字段中
@Autowired
private UserServiceImpl userService;
public void add(){
System.out.println("controller add...");
userService.add();
}
}
注入流程:
在这段代码里,@Autowired 标注在字段 userService 上,作用是告诉 Spring:启动时自动去容器里找类型匹配的 Bean,并赋值给这个字段。这样 add() 方法里调用 userService.add() 时,不需要手动 new UserServiceImpl(),依赖对象的创建和组装全部交给了 Spring 容器(即控制反转 IoC + 依赖注入 DI)。

注入能生效有两个前提:一是 UserServiceImpl 类上通常标注了 @Service(或通过 @Bean、XML 等方式注册进容器),Spring 组件扫描后会把它的实例纳入容器管理;二是 UserController 本身也必须是 Spring Bean------你贴的代码里没看到 @Controller 注解,如果是完整类建议补上,否则 Spring 不会创建它的实例,@Autowired 也就无从注入。
set注入:在setter方法上使用@Autowired注入
注入方式:
Spring 实例化 UserServiceImpl 之后,反射调用带 @Autowired 的 setUserDao() 方法,把容器里的 UserDaoImpl Bean 作为实参传进去。
java
@Service
public class UserServiceImpl implements UserService{
private UserDaoImpl userDao;
public UserDaoImpl getUserDao() {
return userDao;
}
@Autowired
public void setUserDao(UserDaoImpl userDao) {
this.userDao = userDao;
}
@Override
public void add() {
System.out.println("userservice......");
userDao.add();
}
}
构造方法注入
只有一个有参数构造方法,可以无注解注入。如果有多个构造方法,必须写@Autowired注入
JAVA
@Service
public class UserServiceImpl implements UserService{
private UserDaoImpl userDao;
@Autowired
public UserServiceImpl(UserDaoImpl userDao) {
this.userDao = userDao;
}
@Override
public void add() {
System.out.println("userservice......");
userDao.add();
}
}
形参上注入
java
@Service
public class UserServiceImpl implements UserService{
private UserDaoImpl userDao;
public UserServiceImpl(@Autowired UserDaoImpl userDao) {
this.userDao = userDao;
}
@Override
public void add() {
System.out.println("userservice......");
userDao.add();
}
}
@Autowired注解和@Qualifier注解联合使用 Qualifier根据名称进行注入
java
@Service
public class UserServiceImpl implements UserService{
@Autowired
@Qualifier(value = "userRedisDaoImpl")
private UserDao userDao;
// public UserServiceImpl(@Autowired UserDao userDao) {
// this.userDao = userDao;
// }
@Override
public void add() {
System.out.println("user service......");
userDao.add();
}
}
Resource注入
Resource注解也可以完成属性注入。那它和@Autowired注解有什么区别?
Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性(SR-250标准中制定的注解类型。JSR是Java规范提案)- Autowired注解是Spring框架自己的。
- Resource注解默认根据名称装配(byName),未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起使用
- Resource注解用在属性上、setter方法上。Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。
Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖:【如果是JDK8的话不需要额外引入依赖。高于JDK11或低于JDK8需要引入以下依赖。】



value
@vlaue就是个"填空工具":把配置文件里的值自动填到你的 Java 变量里,不用自己写代码读配置
想象你的代码是一道填空题:private String catalog = ____;。这个空总不能写死吧?数据库地址、密钥、开关参数这些东西,得放到配置文件里,换环境时只改文件、不改代码。
它有三种"填法":
| 写法 | 人话 | 例子 |
|---|---|---|
${xxx} |
去配置文件读 xxx 这一项 | @Value("${catalog.name}") |
${xxx:默认值} |
去读 xxx,读不到就用冒号后面的默认值兜底 | @Value("${catalog.name:defaultCatalog}") |
#{表达式} |
不读文件了,直接执行一段 SpEL 表达式算出结果 | @Value("#{systemProperties['user.catalog'] + 'Catalog'}") |
示例:
配置文件 application.properties
properties
catalog.name=MovieCatalog
max.recommendations=5
movie.genres=Thriller,Comedy,Action
配置类
java
@Configuration
@PropertySource("classpath:application.properties") // 告诉 Spring 去哪读配置
public class AppConfig {
// 严格模式开关。
// 默认是"宽松模式":配置项找不到?Spring 不报错,直接把 "${catalog.name}"
// 这个字符串原样塞进变量里,程序照常跑------这个坑很隐蔽。
// 配了这个 bean 之后,任何 ${} 解析不了,Spring 启动直接失败,错误提前暴露。
// 注意:用 JavaConfig 配置时,@Bean 方法必须是 static!
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
// 自定义类型转换器。
// Spring 自带的转换只够应付 int、String[] 这种简单类型,
// 想把字符串转成你自己的类(比如 MovieGenre),就得注册自定义转换器。
@Bean
public ConversionService conversionService() {
DefaultFormattingConversionService service = new DefaultFormattingConversionService();
service.addConverter(new MyCustomConverter()); // 你自己写的"字符串→自定义类型"转换器
return service;
}
}
全部注入姿势
java
@Component
public class MovieRecommender {
// 最基础的用法,注入字符串
// 结果:catalog = "MovieCatalog"
private final String catalog;
// 带默认值。配置文件里没有 not.exist 这一项,
// 结果:backupCatalog = "defaultCatalog"
private final String backupCatalog;
// 自动类型转换。配置里是字符串 "5",自动转成 int
// 结果:maxRecommendations = 5
private final int maxRecommendations;
// 逗号分隔的字符串自动转数组,无需额外工作
// 结果:genres = ["Thriller", "Comedy", "Action"]
private final String[] genres;
// SpEL 表达式,运行时动态计算(取系统属性拼接字符串)
private final String systemCatalog;
// SpEL 还能直接注入复杂结构,比如一个 Map
// 结果:{Thriller=100, Comedy=300}
private final Map<String, Integer> countOfMoviesPerCatalog;
public MovieRecommender(
@Value("${catalog.name}") String catalog,
@Value("${not.exist:defaultCatalog}") String backupCatalog,
@Value("${max.recommendations}") int maxRecommendations,
@Value("${movie.genres}") String[] genres,
@Value("#{systemProperties['user.catalog'] + 'Catalog'}") String systemCatalog,
@Value("#{{'Thriller': 100, 'Comedy': 300}}") Map<String, Integer> countOfMoviesPerCatalog) {
this.catalog = catalog;
this.backupCatalog = backupCatalog;
this.maxRecommendations = maxRecommendations;
this.genres = genres;
this.systemCatalog = systemCatalog;
this.countOfMoviesPerCatalog = countOfMoviesPerCatalog;
}
}
全注解开发
全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文件。
java
package com.light.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.light.www")
public class SpringConfig {
}
测试
java
@Test
public void allDevelop(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserController bean = context.getBean(UserController.class);
bean.add();
}
IOC基于 Java配置类来管理Bean
spring4之后,大多数都是使用基于java的容器配置,放弃基于xml的配置。
Spring 配置支持的核心构件是 @Configuration 注解的类和 @Bean 注解的方法。
@Bean注解用于指示方法实例化、配置并初始化一个新对象,该对象将由 Spring IoC 容器管理。您可以将@Bean注解的方法与任何 Spring@Component一起使用。然而,它们最常与@ConfigurationBean 一起使用。- 用
@Configuration注解一个类,表示 Bean 定义的来源。
register方法
使用 register() 方法对容器进行额外的类注册
java
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppConfig.class, OtherConfig.class);
ctx.register(AdditionalConfig.class);
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
myService.doStuff();
}
scan方法
AnnotationConfigApplicationContext 暴露了 scan(String...) 方法以允许相同的组件扫描功能
java
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("com.acme");
ctx.refresh();
MyService myService = ctx.getBean(MyService.class);
}
@bean
@Bean 是一个方法级别的注解,直接对应 XML 的 <bean/> 元素。该注解支持 <bean/> 提供的一些属性,例如:
init-methoddestroy-methodautowiringname
你可以在 @Configuration 注解的类或 @Component 注解的类中使用 @Bean 注解。
java
package com.light.config;
import com.light.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
//这个也会Spring容器托管,注册到容器中,因为他本来就是一个@Component,和xml作用一样
@Configuration
//自动扫包
@ComponentScan("com.light.pojo")
//导入其他配置类
@Import(xxxConf2.class,xxxConf3.class)
public class BeanConfig {
//注册一个bean,就相当于我们之前写的一个xml的bean标签
//这个方法的名字,就相当于bean标签中的id属性
//这个方法的返回值,就相当于bean标签中的cLass属性
@Bean
public User getUser(){
return new User();
}
}
也可以用接口(或基类)返回类型声明你的 @Bean 方法,然而,这限制了高级类型预测对指定接口类型的可见性。
一个 @Bean 注解的方法可以有任意数量的参数,这些参数描述了构建该 bean 所需的依赖项。例如,如果我们的 TransferService 需要一个 AccountRepository,我们可以使用方法参数来实现该依赖项
java
@Configuration
public class AppConfig {
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
}
bean也支持接收生命周期回调
任何用 @Bean 注解定义的类都支持常规的生命周期回调,并且可以使用 JSR-250 的 @PostConstruct 和 @PreDestroy 注解
常规的 Spring 生命周期回调也完全支持。如果一个 bean 实现了 InitializingBean、DisposableBean 或 Lifecycle,容器会调用它们各自的方法。
标准的一组 *Aware 接口(例如 BeanFactoryAware、BeanNameAware、MessageSourceAware、ApplicationContextAware 等)也完全支持
@Bean 注解支持指定任意初始化和销毁回调方法,就像 Spring XML 中 bean 元素上的 init-method 和 destroy-method 属性一样,如下例所示:
java
public class BeanOne {
public void init() {
// initialization logic
}
}
public class BeanTwo {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public BeanOne beanOne() {
return new BeanOne();
}
@Bean(destroyMethod = "cleanup")
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
使用 @Scope 注解, 默认范围是 singleton
java
@Configuration
public class MyConfiguration {
@Bean
@Scope("prototype")
public Encryptor encryptor() {
// ...
}
}
IOC原理
java 反射机制
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为ava 语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。
要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关API
(1) java.lang.Class (2) java.lang.reflect ,所以,Class对象是反射的根源。