依赖查找和依赖注入
依赖查找和依赖注入,是在Spring环境下获取实际对象的方式(基于IoC容器)。依赖查找偏主动,依赖注入偏被动。
依赖查找
依赖查找可以通过名称、类型和注解等三种方式实现查找。
依赖注入
依赖注入主要通过注解实现对象自动获取,不需要显示编码实现,常用语SpringBoot的框架中。此方式方便快速,理解上也相对简单。
配置Bean对象及信息
在配置对象信息时,可以通过设置Bean配置文件、配置autowire实现和@Configuration+@Bean实现。
设置Bean配置文件
可以通过设置Bean配置文件实现Bean对象及信息配置。
例如:
<?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/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">
<bean id="user" class="springtest.ioc.overview.domain.User">
<property name="id" value="1"/>
<property name="name" value="xiaoming"/>
</bean>
<bean id="superUser" class="springtest.ioc.overview.domain.SuperUser" parent="user" primary="true">
<property name="address" value="Hangzhou"/>
</bean>
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
上面代码中描述了三个Bean定义:
1、id:表示该Bean定义的编号,在后续通过依赖查找时,可依据id查找到该对象;
2、class:指定到该Bean类;
3、property:指定该Bean类对应的属性值;
4、parent:指定该类的父类对应的id;
5、primary:指定该类在同类(包含子类和父类)中被优先提取(一般基于类型的依赖查找时)。
配置autowire实现
同样,也可以通过在Bean配置文件的Bean定义时,使用autowire实现:
<?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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!-- 通过导入复用 dependency-lookup-context.xml -->
<import resource="dependency-lookup-context.xml"/>
<!-- Auto Writing -->
<bean id="userRepository" class="springtest.ioc.overview.repository.UserRepository" autowire="byType">
<!-- 手动配置 -->
<!-- <property name="users">-->
<!-- <util:list>-->
<!-- <ref bean="superUser"/>-->
<!-- <ref bean="user"/>-->
<!-- </util:list>-->
<!-- </property>-->
</bean>
</beans>
上面代码中描述了Bean定义:
1、autowire:表示该Bean通过类型查找实现自动匹配;
@Configuration+@Bean实现
package springtest.ioc.overview.container;
import javafx.application.Application;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springtest.ioc.overview.domain.User;
import java.util.Map;
/**
* 注解能力 @ApplicationContext作为 IoC 容器示例
*/
@Configuration
public class AnnotationApplicationContextAsIoCContainerDemo {
public static void main(String[] args) {
//创建 BeanFactory 容器
// DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//将当前类 AnnotationApplicationContextAsIoCContainerDemo作为配置类
applicationContext.register(AnnotationApplicationContextAsIoCContainerDemo.class);
//启动应用上下文
applicationContext.refresh();
//依赖查找集合对象
lookupByColleactionType(applicationContext);
//关闭应用上下文
applicationContext.close();
}
@Bean
public User user(){
User user = new User();
user.setId(1L);
user.setName("xiaohhong");
return user;
}
private static void lookupByColleactionType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("实时(集合类型)查找:" + users);
}
}
}
上面代码中,通过在类前加@Configuration说明本类是一个配置类,在user()方法前加@Bean,表示该方法返回的对象User为Bean类,可用于自动注入。
然后将该类注入到IoC容器中,即将bean类加入到容器中,后续可实现依赖注入。
在方法lookupByColleactionType中,看到了通过类型查找User,使用的就是依赖注入。
应用实例
代码结构
依赖查找配置文件 dependency-lookup-context.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/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">
<bean id="user" class="springtest.ioc.overview.domain.User">
<property name="id" value="1"/>
<property name="name" value="xiaoming"/>
</bean>
<bean id="superUser" class="springtest.ioc.overview.domain.SuperUser" parent="user" primary="true">
<property name="address" value="Hangzhou"/>
</bean>
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
依赖查找测试代码 DependencyLookupDemo.java
package springtest.ioc.overview.dependency.lookup;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.ioc.overview.annotation.Super;
import springtest.ioc.overview.domain.SuperUser;
import springtest.ioc.overview.domain.User;
import java.util.Map;
/**
* 依赖查找示例
* 1、通过名称查找
* 2、通过类型查找
*/
public class DependencyLookupDemo {
public static void main(String[] args) {
//配置 xml 配置文件
//启动 Spring 应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml");
//按照id实时查找
lookupInRealTime(beanFactory);
//按照id延迟查找
lookInLazy(beanFactory);
//按照类型查找
lookupByType(beanFactory);
//按照集合类型查找
lookupByColleactionType(beanFactory);
//通过注解查找
lookupByAnnotationType(beanFactory);
}
public static void lookupInRealTime(BeanFactory beanFactory) {
User user = (User) beanFactory.getBean("user");
System.out.println("实时查找:" + user);
}
private static void lookInLazy(BeanFactory beanFactory) {
ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
User user = objectFactory.getObject();
System.out.println("延迟查找:" + user);
}
private static void lookupByType(BeanFactory beanFactory) {
User user = beanFactory.getBean(User.class);
System.out.println("实时(类型)查找:" + user);
}
private static void lookupByColleactionType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("实时(集合类型)查找:" + users);
}
}
private static void lookupByAnnotationType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println("查找标注@Super的用户集合:" + users);
}
}
}
依赖注入配置文件 dependency-injection-context.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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!-- 通过导入复用 dependency-lookup-context.xml -->
<import resource="dependency-lookup-context.xml"/>
<!-- Auto Writing -->
<bean id="userRepository" class="springtest.ioc.overview.repository.UserRepository" autowire="byType">
<!-- 手动配置 -->
<!-- <property name="users">-->
<!-- <util:list>-->
<!-- <ref bean="superUser"/>-->
<!-- <ref bean="user"/>-->
<!-- </util:list>-->
<!-- </property>-->
</bean>
</beans>
依赖注入测试代码 DependencyInjectionDemo.java
package springtest.ioc.overview.dependency.injection;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.Environment;
import springtest.ioc.overview.annotation.Super;
import springtest.ioc.overview.domain.User;
import springtest.ioc.overview.repository.UserRepository;
import java.util.Map;
/**
* 依赖注入示例
* 1、通过名称查找
* 2、通过类型查找
*/
public class DependencyInjectionDemo {
public static void main(String[] args) {
//配置 xml 配置文件
//启动 Spring 应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-injection-context.xml");
// 依赖来源一:自定义 Bean
UserRepository userRepository = beanFactory.getBean("userRepository", UserRepository.class);
System.out.println(userRepository.getUsers());
//依赖来源二:依赖注入(内建依赖)
System.out.println(userRepository.getBeanFactory());
// System.out.println(userRepository.getBeanFactory() == beanFactory);
ObjectFactory objectFactory = userRepository.getObjectFactory();
System.out.println(objectFactory.getObject());
//依赖查找
// System.out.println(beanFactory.getBean(BeanFactory.class));
//依赖来源三:容器内建 Bean
Environment environment = beanFactory.getBean(Environment.class);
System.out.println("获取 environment 类型的 Bean:" + environment);
whoIsIoCContainer(userRepository, applicationContext);
}
private static void whoIsIoCContainer(UserRepository userRepository, ApplicationContext applicationContext) {
// ConfigurableApplicationContext <- ApplicationContext <- BeanFactory
// ConfigurableApplicationContext#getBeanFactory()
// 这个表达式为什么不会成立
System.out.println(userRepository.getBeanFactory() == applicationContext);
// ApplicationContext is BeanFactory
}
}
其他代码
Super 注解类
package springtest.ioc.overview.annotation;
import java.lang.annotation.*;
/**
* 超级
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Super {
}
User类
package springtest.ioc.overview.domain;
/**
* 用户类
*/
public class User {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long 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 + '\'' +
'}';
}
}
SuperUser类
package springtest.ioc.overview.domain;
import springtest.ioc.overview.annotation.Super;
@Super
public class SuperUser extends User{
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "SuperUser{" +
"address='" + address + '\'' +
"} " + super.toString();
}
}
UserRepository
package springtest.ioc.overview.repository;
import javafx.application.Application;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import springtest.ioc.overview.domain.User;
import java.util.Collection;
/**
* 用户的信息仓库
*/
public class UserRepository {
//自定义 Bean
private Collection<User> users;
//内建非 Bean 对象(依赖)
private BeanFactory beanFactory;
private ObjectFactory<User> objectFactory;
public Collection<User> getUsers() {
return users;
}
public void setUsers(Collection<User> users) {
this.users = users;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
public ObjectFactory<User> getObjectFactory() {
return objectFactory;
}
public void setObjectFactory(ObjectFactory<User> objectFactory) {
this.objectFactory = objectFactory;
}
}
BeanFactoryAsIoCContainerDemo
package springtest.ioc.overview.container;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import springtest.ioc.overview.domain.User;
import java.util.Map;
/**
* 作为 IoC 容器示例
*/
public class BeanFactoryAsIoCContainerDemo {
public static void main(String[] args) {
//创建 BeanFactory 容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//加载配置
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
//Xml 配置文件 ClassPath 路径
String location = "classpath:/META-INF/dependency-lookup-context.xml";
System.out.println("number beans:" + reader.loadBeanDefinitions(location));
//依赖查找集合对象
lookupByColleactionType(beanFactory);
}
private static void lookupByColleactionType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("实时(集合类型)查找:" + users);
}
}
}
运行结构
AnnotationApplicationContextAsIoCContainerDemo
package springtest.ioc.overview.container;
import javafx.application.Application;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springtest.ioc.overview.domain.User;
import java.util.Map;
/**
* 注解能力 @ApplicationContext作为 IoC 容器示例
*/
@Configuration
public class AnnotationApplicationContextAsIoCContainerDemo {
public static void main(String[] args) {
//创建 BeanFactory 容器
// DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//将当前类 AnnotationApplicationContextAsIoCContainerDemo作为配置类
applicationContext.register(AnnotationApplicationContextAsIoCContainerDemo.class);
//启动应用上下文
applicationContext.refresh();
//依赖查找集合对象
lookupByColleactionType(applicationContext);
//关闭应用上下文
applicationContext.close();
}
@Bean
public User user(){
User user = new User();
user.setId(1L);
user.setName("xiaohhong");
return user;
}
private static void lookupByColleactionType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("实时(集合类型)查找:" + users);
}
}
}
运行结果
应用实例2
应用实例2引入别名 alias 和 BeanDefinition 相关操作。
代码结构图
架构配置 bean-definition-context.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/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">
<!-- 导入第三方 Spring xml 配置文件 -->
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<!-- 将 Spring 中的 "user" Bean 关联/建立 别名 "szc-user"-->
<alias name="user" alias="szc-user"/>
</beans>
上述代码通过 + resource方式引入了应用实例1的项目配置,同时同归 + name + alias方式为user增加了别名。
验证别名的作用
package springtest.bean.definition;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.ioc.overview.domain.User;
/**
* Bean 的别名示例
*/
public class BeanAliasDemo {
public static void main(String[] args) {
//配置 xml 配置文件
//启动 Spring 应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-definition-context.xml");
//通过别名 "szc-user" 获取 User 的 Bean
User userAlias = (User)beanFactory.getBean("szc-user");
User userOrigin = (User)beanFactory.getBean("user");
System.out.println("userAlias == userOrigin ? :" + (userAlias == userOrigin));
}
}
上述代码通过名称获取了user的bean对象,一个用的时真名,一个用的时别名。
BeanDefinition 使用(通过代码定义和创建bean)
package springtest.bean.definition;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import springtest.ioc.overview.domain.User;
/**
* BeanDefinition 构建示例
*/
public class BeanDefinitionCreationDemo {
public static void main(String[] args) {
//1. 通过 BeanDefinitionBuilder 构建 Bean 类型(配置文件都不用写)
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
//通过水泥杆设置
beanDefinitionBuilder.addPropertyValue("id", 34);
beanDefinitionBuilder.addPropertyValue("name", "nihaoa");
//获取 BeanDefinition 实例
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
//BeanDefinition 并非 Bean 的最终状态
System.out.println(beanDefinition.getBeanClassName());
//2. 通过 AbstractBeanDefinition 以及派生类构建 Bean 类型(配置文件都不用写)
GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
//设置 Bean 的类型
genericBeanDefinition.setBeanClass(User.class);
//通过 MultablePropertyValues 批量操作属性
MutablePropertyValues propertyValues = new MutablePropertyValues();
// propertyValues.addPropertyValue("id", 43);
// propertyValues.addPropertyValue("name", "nihaoa2");
propertyValues.add("id", 55);
propertyValues.add("name", "nihaoa3");
//通过 set MultablePropertyValues 批量操作属性
genericBeanDefinition.setPropertyValues(propertyValues);
}
}
上述代码分别通过BeanDefinition和AbstractBeanDefinition定义bean对象,没有使用项目配置文件定位,是一种创建bean的新方案。
通过 AnnotationConfigApplicationContext 创建bean
package springtest.bean.definition;
import javafx.beans.binding.ObjectExpression;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import springtest.ioc.overview.domain.User;
import java.util.Map;
/**
* 注解 BeanDefinition 示例
*/
@Import(AnnotationBeanDefinitionDemo.Config.class)//3.通过 @Import 方式导入
public class AnnotationBeanDefinitionDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类)
applicationContext.register(Config.class);
//启动应用上下文
applicationContext.refresh();
//通过 BeanDefinition 注册 API 实现
//1.命名 bean 的注册方式
registerBeanDefinition(applicationContext, "szc-2-user");
//2.非命名 bean 的注册方式
registerBeanDefinition(applicationContext, "");
//1.通过 @Bean 方式进行定义
//2.通过 @Component 方式进行定义
//3.通过 @Import 方式导入
Map<String, Config> configBeans = applicationContext.getBeansOfType(Config.class);
System.out.println("Config 类型的所有 Beans:" + applicationContext.getBeansOfType(Config.class));
System.out.println("User 类型的所有 Beans:" + applicationContext.getBeansOfType(User.class));
//关闭应用上下文
applicationContext.close();
}
/**
* 命名 Bean 的注册方式
*
* @param registry
* @param beanName
*/
public static void registerBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
beanDefinitionBuilder.addPropertyValue("id", 2L);
beanDefinitionBuilder.addPropertyValue("name", "xiaoming");
//判断如果 beanName 参数存在时
if (StringUtils.hasText(beanName)) {
//注册 BeanDefinition
registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
} else {
//非命名 bean 的注册方式
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
}
}
@Component //定义当前类作为 Spring Bean 组件//2.通过 @Component 方式进行定义
public static class Config {
@Bean(name = {"user", "szc-user"})//1.通过 @Bean 方式进行定义
public User user() {
User user = new User();
user.setId(1L);
user.setName("xiaohhong");
return user;
}
}
}
上述代码通过注解@Import导入配置类,并在配置类上使用@Bean注解,然后通过查类型的方式获取bean对象。
运行结果
应用实例3
应用实例3衔接应用实例2。
实例应用3实现静态方法\调用实例Bean静态方法和通过FactoryBean获得Bean对象。
代码结构图
User类
相对一应用实例2的User类,增加了public静态方法createUser:
package springtest.ioc.overview.domain;
/**
* 用户类
*/
public class User {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long 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 + '\'' +
'}';
}
/**
* 静态方法构建 bean
* @return
*/
public static User createUser(){
User user = new User();
user.setId(1L);
user.setName("xiaohhong");
return user;
}
}
用户工厂接口 UserFactory
接口包含默认方法createUser:
package springtest.bean.definition.factory;
import springtest.ioc.overview.domain.User;
public interface UserFactory {
default User createUser(){
return User.createUser();
}
}
UserFactory接口实现类 DefaultUserFactory
使用接口默认实现:
package springtest.bean.definition.factory;
import springtest.ioc.overview.domain.User;
public class DefaultUserFactory implements UserFactory {
}
创建 UserFactoryBean类,实现FactoryBean接口
package springtest.bean.definition.factory;
import org.springframework.beans.factory.FactoryBean;
import springtest.ioc.overview.domain.User;
/**
* FactoryBean 的实现
*/
public class UserFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
return User.createUser();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
配置文件 bean-instantiation-context.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/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">
<!-- 静态方法实例化 Bean -->
<bean id="user-by-static-method" class="springtest.ioc.overview.domain.User"
factory-method="createUser"/>
<!-- 实例 (Bean) 方法实例化 Bean -->
<bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/>
<bean id="userFactory" class="springtest.bean.definition.factory.DefaultUserFactory"/>
<!-- FactoryBean 实例化 Bean-->
<bean id="user-by-factory-bean" class="springtest.bean.definition.factory.UserFactoryBean"/>
</beans>
包含静态方法实例化Bean、实例方法实例化Bean和FactoryBean方法。
factory-method指向类中的静态方法,factory-bean指向实例Bean。
调试类 BeanInstantiationDemo
package springtest.bean.definition;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.ioc.overview.domain.User;
/**
* Bean 实例化
*/
public class BeanInstantiationDemo {
public static void main(String[] args) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/bean-instantiation-context.xml");
User user = beanFactory.getBean("user-by-static-method", User .class);
User userByInstanceMethod = beanFactory.getBean("user-by-instance-method", User .class);
User userByFactoryBean = beanFactory.getBean("user-by-factory-bean", User .class);
System.out.println(user);
System.out.println(userByInstanceMethod);
System.out.println(user == userByInstanceMethod);
System.out.println(user == userByFactoryBean);
System.out.println(user == userByInstanceMethod);
}
}
运行结果
应用实例4
应用实例4衔接应用实例3,主要讲解ServiceLoader加载Bean。
代码结构图
创建 springtest.bean.definition.factory.UserFactory
在resource下创建service路径,然后创建springtest.bean.definition.factory.UserFactory。该文件名指向将使用的生成User的接口,其内容是接口实现类的路径:
springtest.bean.definition.factory.DefaultUserFactory
创建配置文件 special-bean-instantiation-context.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/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">
<!-- ServiceLoader实例化 Bean -->
<bean id="userFactoryServiceLoader" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
<property name="serviceType" value="springtest.bean.definition.factory.UserFactory"/>
</bean>
</beans>
该配置文件主要定义了ServiceFactoryBean类,并将其serviceType指向UserFactory接口(之后该接口通过前面讲解的service目录下的文件,找到对应的接口实现类)。
测试类SpecialBeanInstantiationDemo
package springtest.bean.definition;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.bean.definition.factory.DefaultUserFactory;
import springtest.bean.definition.factory.UserFactory;
import springtest.ioc.overview.domain.User;
import java.util.Iterator;
import java.util.ServiceLoader;
import static java.util.ServiceLoader.load;
/**
* Bean 实例化
*/
public class SpecialBeanInstantiationDemo {
public static void main(String[] args) {
//配置 XML 配置文件
//启动 Spring 应用上下文
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/META-INF/special-bean-instantiation-context.xml");
//通过 AppliccationContext 获取 AutowireCapableBeanFactory
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
ServiceLoader<UserFactory> serviceLoader = beanFactory.getBean("userFactoryServiceLoader", ServiceLoader.class);
displayServiceLoader(serviceLoader);
demoServiceLoader();
//创建 UserFactory 对象,通过 AutowireCapableBeanFactory
UserFactory userFactory = beanFactory.createBean(DefaultUserFactory.class);
System.out.println(userFactory.createUser());
}
public static void demoServiceLoader() {
ServiceLoader<UserFactory> serviceLoader = load(UserFactory.class, Thread.currentThread().getContextClassLoader());
displayServiceLoader(serviceLoader);
}
public static void displayServiceLoader(ServiceLoader<UserFactory> serviceLoader){
Iterator<UserFactory> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
UserFactory userFactory = iterator.next();
System.out.println(userFactory.createUser());
}
}
}
运行结果
应用实例5
应用实例5衔接应用实例4,主要讲解Bean的三种初始化方法:
1、@PostConstruct;
2、InitializingBean的afterPropertiesSet();
3、@Bean(initMethod="…")。
代码架构
DefaultUserFactory 修改
package springtest.bean.definition.factory;
import org.springframework.beans.factory.InitializingBean;
import springtest.ioc.overview.domain.User;
import javax.annotation.PostConstruct;
public class DefaultUserFactory implements UserFactory, InitializingBean {
//1.基于 @PostConstruct 注解
@PostConstruct
public void init(){
System.out.println("@PostConstruct: UserFactory 初始化中...(优先级1)");
}
public void initUserFactory(){
System.out.println("自定义初始化方法:initUserFactory() UserFactory 初始化中...(优先级3)");
}
//3.基于 InitializingBean:afterPropertiesSet()
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean:afterPropertiesSet() UserFactory 初始化中...(优先级2)");
}
}
BeanInitializationDemo
package springtest.bean.definition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springtest.bean.definition.factory.DefaultUserFactory;
import springtest.bean.definition.factory.UserFactory;
@Configuration
public class BeanInitializationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration class (配置类)
applicationContext.register(BeanInitializationDemo.class);
//启动 Spring 上下文
applicationContext.refresh();
// 依赖查找 UserFactory
// UserFactory userFactory = (UserFactory)applicationContext.getBean("userFactory");
UserFactory userFactory = applicationContext.getBean(UserFactory.class);
//关闭 Spring 上下文
applicationContext.close();
}
//2.基于 initMethod 指定初始化方法
@Bean(initMethod = "initUserFactory")
public UserFactory userFactory() {
return new DefaultUserFactory();
}
}
运行结果
应用实例6
应用实例6衔接应用实例5,主要讲解Bean的延迟初始化方法:
通过在@Bean类前加上@Lazy注释;如果写成@Lazy(value = false),表示为非延迟初始化。
BeanInitializationDemo
package springtest.bean.definition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springtest.bean.definition.factory.DefaultUserFactory;
import springtest.bean.definition.factory.UserFactory;
@Configuration
public class BeanInitializationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration class (配置类)
applicationContext.register(BeanInitializationDemo.class);
//启动 Spring 上下文
applicationContext.refresh();
// 依赖查找 UserFactory
// UserFactory userFactory = (UserFactory)applicationContext.getBean("userFactory");
UserFactory userFactory = applicationContext.getBean(UserFactory.class);
//关闭 Spring 上下文
applicationContext.close();
}
//2.基于 initMethod 指定初始化方法
@Bean(initMethod = "initUserFactory")
@Lazy//(value = false)
public UserFactory userFactory() {
return new DefaultUserFactory();
}
}
运行结果
1、@Lazy:延迟初始化
2、@Lazy(value = false):非延迟初始化
应用实例7
应用实例7衔接应用实例6,主要讲解Bean的销毁方法:
1、@PreDestroy;
2、DestroyBean的destroy();
3、@Bean(destroyMethod="…")。
DefaultUserFactory
package springtest.bean.definition.factory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import springtest.ioc.overview.domain.User;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class DefaultUserFactory implements UserFactory, InitializingBean , DisposableBean {
//1.基于 @PostConstruct 注解
@PostConstruct
public void init(){
System.out.println("@PostConstruct: UserFactory 初始化中...(优先级1)");
}
public void initUserFactory(){
System.out.println("自定义初始化方法:initUserFactory() UserFactory 初始化中...(优先级3)");
}
//3.基于 InitializingBean:afterPropertiesSet()
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean:afterPropertiesSet() UserFactory 初始化中...(优先级2)");
}
@PreDestroy
public void preDestroy(){
System.out.println("@PreDestroy : UserFactory 销毁中 ...(优先级1)");
}
@Override
public void destroy() throws Exception {
System.out.println("@DisposableBean#destroy() : UserFactory 销毁中 ...(优先级2)");
}
public void doDestroy(){
System.out.println("自定义初始化方法#doDestroy() : UserFactory 销毁中 ...(优先级3)");
}
}
BeanInitializationDemo
package springtest.bean.definition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import springtest.bean.definition.factory.DefaultUserFactory;
import springtest.bean.definition.factory.UserFactory;
@Configuration
public class BeanInitializationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration class (配置类)
applicationContext.register(BeanInitializationDemo.class);
//启动 Spring 上下文
applicationContext.refresh();
//非延迟初始化在 Spring 应用上下文启动完成后,被初始化
System.out.println("Spring 应用上下文启动完成...");
// 依赖查找 UserFactory
// UserFactory userFactory = (UserFactory)applicationContext.getBean("userFactory");
UserFactory userFactory = applicationContext.getBean(UserFactory.class);
System.out.println(userFactory);
System.out.println("Spring 应用上下文准备关闭...");
//关闭 Spring 上下文
applicationContext.close();
System.out.println("Spring 应用上下文关闭完成...");
}
//2.基于 initMethod 指定初始化方法
@Bean(initMethod = "initUserFactory", destroyMethod = "doDestroy")
@Lazy(value = false)
public UserFactory userFactory() {
return new DefaultUserFactory();
}
}
运行结果
应用实例8
应用实例8衔接应用实例7,主要讲解Spring垃圾回收GC:
1、通过上下文close()时,调用finialize()方法实现:
代码架构
DefaultUserFactory
package springtest.bean.definition.factory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import springtest.ioc.overview.domain.User;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class DefaultUserFactory implements UserFactory, InitializingBean, DisposableBean {
//1.基于 @PostConstruct 注解
@PostConstruct
public void init() {
System.out.println("@PostConstruct: UserFactory 初始化中...(优先级1)");
}
public void initUserFactory() {
System.out.println("自定义初始化方法:initUserFactory() UserFactory 初始化中...(优先级3)");
}
//3.基于 InitializingBean:afterPropertiesSet()
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean:afterPropertiesSet() UserFactory 初始化中...(优先级2)");
}
@PreDestroy
public void preDestroy() {
System.out.println("@PreDestroy : UserFactory 销毁中 ...(优先级1)");
}
@Override
public void destroy() throws Exception {
System.out.println("@DisposableBean#destroy() : UserFactory 销毁中 ...(优先级2)");
}
public void doDestroy() {
System.out.println("自定义初始化方法#doDestroy() : UserFactory 销毁中 ...(优先级3)");
}
@Override
public void finalize() throws Throwable {
System.out.println("当前 DefaultUserFactory 对象正在被垃圾回收");
}
}
BeanGarbageColleationDemo
package springtest.bean.definition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import springtest.bean.definition.factory.UserFactory;
/**
* Bean 垃圾回收(GC) 示例
*/
public class BeanGarbageColleationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration class (配置类)
applicationContext.register(BeanInitializationDemo.class);
//启动 Spring 上下文
applicationContext.refresh();
//关闭 Spring 上下文
applicationContext.close();
System.out.println("Spring 应用上下文关闭完成...");
//强制出发 GC
System.gc();
}
}
运行结果
应用实例9
应用实例9衔接应用实例8,单体 Bean 注册实例:
1、注册外部单例对象,.registerSingleton(…):
代码架构
SingletonBeanRegistrationDemo
package springtest.bean.definition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import springtest.bean.definition.factory.DefaultUserFactory;
import springtest.bean.definition.factory.UserFactory;
/**
* 单体 Bean 注册实例
*/
public class SingletonBeanRegistrationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 创建外部单例对象
UserFactory userFactory = new DefaultUserFactory();
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
// 注册外部单例对象
beanFactory.registerSingleton("userFactory", userFactory);
//启动 Spring 上下文
applicationContext.refresh();
//通过依赖查找的方式来获取 UserFactory
UserFactory userFactoryByLookup = beanFactory.getBean("userFactory", UserFactory.class);
System.out.println("userFactory == userFactoryByLookup:" + (userFactory == userFactoryByLookup));
//关闭 Spring 上下文
applicationContext.close();
}
}
运行结果
应用实例10
应用实例10,单一类型依赖查找实例:
1、涉及到ObjectProvider:
代码架构
ObjectProviderDemo
package springtest.dependency.lookup;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
/**
* 通过 PbjectProvider 进行依赖查找
*/
public class ObjectProviderDemo { // @Configuration 是非必须注解
public static void main(String[] args) {
//创建 BeanFactory 容器
// DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//将当前类 ObjectProviderDemo 作为配置类
applicationContext.register(ObjectProviderDemo.class);
//启动应用上下文
applicationContext.refresh();
//依赖查找集合对象
lookupByObjectProvider(applicationContext);
//关闭应用上下文
applicationContext.close();
}
@Bean
public String helloworld(){ // 方法名就是 Bean 名称 = "helloworld"
return "Hello, World!";
}
private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
System.out.println(objectProvider.getObject());
}
}
1、在使用ObjectProvider时,可以不需要再类前注明@Configuration注释;
2、加上@Bean注释后,方法名就变成了Bean名称;
3、上下文对象通过getBeanProvider获得ObjectProvider对象,然后ObjectProvider对象通过getObject方法获得对象。
运行结果
应用实例11
应用实例11,主讲层次依赖查找:
1、涉及到ConfigurableListableBeanFactory类的getParentBeanFactory()方法和HierarchicalBeanFactory类的setParentBeanFactory()方法,用来实现对父类的提取和设置。
代码架构
HierarchicalDependencyLookupDemo
package springtest.dependency.lookup;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 层次性依赖查找示例
*/
public class HierarchicalDependencyLookupDemo {
public static void main(String[] args) {
//创建 BeanFactory 容器
// DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//将当前类 ObjectProviderDemo 作为配置类
applicationContext.register(HierarchicalDependencyLookupDemo.class);
//1. 获取 HierarchicalBeanFactory <- ConfigurableBeanFactory <- ConfigurableListableBeanFactory
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
System.out.println("当前 BeanFactory 的 Parent BeanFactory:" + beanFactory.getParentBeanFactory());
//2. 设置 Parent BeanFactory
HierarchicalBeanFactory parentBeanFactory = createParentBeanFactory();
beanFactory.setParentBeanFactory(createParentBeanFactory());
System.out.println("当前 BeanFactory 的 Parent BeanFactory:" + beanFactory.getParentBeanFactory());
displayContainsLocalBean(beanFactory, "user");
displayContainsLocalBean(parentBeanFactory, "user");
displayContainsBean(beanFactory, "user");
displayContainsBean(parentBeanFactory, "user");
//启动应用上下文
applicationContext.refresh();
//关闭应用上下文
applicationContext.close();
}
private static void displayContainsBean(HierarchicalBeanFactory beanFactory, String beanName) {
System.out.printf("当前 BeanFactory[name: %s] 是否包含 bean[name: %s]: %s\n", beanFactory, beanName,
containsBean(beanFactory, beanName));
}
private static boolean containsBean(HierarchicalBeanFactory beanFactory, String beanName){
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
if (parentBeanFactory instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory parentHierarchicalBeanFactory = HierarchicalBeanFactory.class.cast(parentBeanFactory);
if(containsBean(parentHierarchicalBeanFactory, beanName)){
return true;
}
}
return beanFactory.containsLocalBean(beanName);
}
private static void displayContainsLocalBean(HierarchicalBeanFactory beanFactory, String beanName) {
System.out.printf("当前 BeanFactory[name: %s] 是否包含 local bean[name: %s]: %s\n", beanFactory, beanName,
beanFactory.containsLocalBean(beanName));
}
private static ConfigurableListableBeanFactory createParentBeanFactory() {
//创建 BeanFactory 容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//加载配置
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
//Xml 配置文件 ClassPath 路径
String location = "classpath:/META-INF/dependency-lookup-context.xml";
reader.loadBeanDefinitions(location);
return beanFactory;
}
}
1、通过ConfigurableListableBeanFactory类的getParentBeanFactory()方法提取父类;
2、通过HierarchicalBeanFactory类的setParentBeanFactory()方法设置父类。
运行结果
/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=50804:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/tools.jar:/Users/susie/_my_java/Spring/geekbang-lessons-master/springtest/dependency-lookup/target/classes:/Users/susie/.m2/repository/org/springframework/spring-context/5.2.2.RELEASE/spring-context-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-aop/5.2.2.RELEASE/spring-aop-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-beans/5.2.2.RELEASE/spring-beans-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-core/5.2.2.RELEASE/spring-core-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-jcl/5.2.2.RELEASE/spring-jcl-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-expression/5.2.2.RELEASE/spring-expression-5.2.2.RELEASE.jar:/Users/susie/_my_java/Spring/geekbang-lessons-master/springtest/ioc-container-overview/target/classes:/Users/susie/.m2/repository/org/springframework/spring-jdbc/5.2.2.RELEASE/spring-jdbc-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-tx/5.2.2.RELEASE/spring-tx-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-webflux/5.2.2.RELEASE/spring-webflux-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/org/springframework/spring-web/5.2.2.RELEASE/spring-web-5.2.2.RELEASE.jar:/Users/susie/.m2/repository/io/projectreactor/reactor-core/3.3.1.RELEASE/reactor-core-3.3.1.RELEASE.jar:/Users/susie/.m2/repository/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar:/Users/susie/.m2/repository/org/springframework/spring-webmvc/5.2.2.RELEASE/spring-webmvc-5.2.2.RELEASE.jar springtest.dependency.lookup.HierarchicalDependencyLookupDemo
当前 BeanFactory 的 Parent BeanFactory:null
当前 BeanFactory 的 Parent BeanFactory:org.springframework.beans.factory.support.DefaultListableBeanFactory@2a2d45ba: defining beans [user,superUser,objectFactory]; root of factory hierarchy
当前 BeanFactory[name: org.springframework.beans.factory.support.DefaultListableBeanFactory@4678c730: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,hierarchicalDependencyLookupDemo]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@2a2d45ba] 是否包含 local bean[name: user]: false
当前 BeanFactory[name: org.springframework.beans.factory.support.DefaultListableBeanFactory@6767c1fc: defining beans [user,superUser,objectFactory]; root of factory hierarchy] 是否包含 local bean[name: user]: true
当前 BeanFactory[name: org.springframework.beans.factory.support.DefaultListableBeanFactory@4678c730: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,hierarchicalDependencyLookupDemo]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@2a2d45ba] 是否包含 bean[name: user]: true
当前 BeanFactory[name: org.springframework.beans.factory.support.DefaultListableBeanFactory@6767c1fc: defining beans [user,superUser,objectFactory]; root of factory hierarchy] 是否包含 bean[name: user]: true
Process finished with exit code 0
应用实例12
应用实例12,主讲通过ObjectProvider进行Bean查找:
1、通过调用applicationContext.getBeanProvider(类型类名)方法获得带类型参数的ObjectProvider对象;
2、ObjectProvider对象通过方法getObject())获得对象;
3、ObjectProvider对象通过方法getIfAvailable(lambda表达式,返回的是Bean对象)获得对象(lambda返回的表达式);
4、ObjectProvider对象通过迭代器,循环获得对象;
5、ObjectProvider对象通过调用stream()方法,循环获得对象;
代码架构
ObjectProviderDemo
package springtest.dependency.lookup;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import springtest.ioc.overview.domain.User;
/**
* 通过 PbjectProvider 进行依赖查找
*/
public class ObjectProviderDemo { // @Configuration 是非必须注解
public static void main(String[] args) {
//创建 BeanFactory 容器
// DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//将当前类 ObjectProviderDemo 作为配置类
applicationContext.register(ObjectProviderDemo.class);
//启动应用上下文
applicationContext.refresh();
//依赖查找集合对象
lookupByObjectProvider(applicationContext);
lookupIfAvailable(applicationContext);
lookupByStreamOps(applicationContext);
//关闭应用上下文
applicationContext.close();
}
private static void lookupByStreamOps(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
// 1.通过迭代实现
Iterable<String> stringIterable = objectProvider;
for(String string : stringIterable){
System.out.println(string);
}
// 2.通过 Stream 实现
objectProvider.stream().forEach(System.out::println);
}
private static void lookupIfAvailable(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
User user = userObjectProvider.getIfAvailable(() -> User.createUser());
System.out.println("当前 User 对象:" + user);
}
private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
System.out.println(objectProvider.getObject());
}
@Bean
@Primary
public String helloworld() { // 方法名就是 Bean 名称 = "helloworld"
return "Hello, World!";
}
@Bean
public String message() { // 方法名就是 Bean 名称 = "helloworld"
return "message";
}
}
运行结果
应用实例13
应用实例13,主讲线程安全操作
1、 BeanFactory#getBean 方法线程不安全,无对象将报错;
2、ObjectFactory#getObject 方法线程不安全,无对象将报错;
3、ObjectProvider#getIfAvailable 方法线程安全,无对象不报错;
4、ListableBeanFactory#getBeanOfType 方法线程安全,无对象不报错;
5、ObjectProvider#Stream 方法线程安全,无对象不报错。
代码架构
TypeSfaetyDependencyLookupDemo
package springtest.dependency.lookup;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.w3c.dom.ls.LSOutput;
import springtest.ioc.overview.domain.User;
/**
* 线程安全操作示例
*/
public class TypeSfaetyDependencyLookupDemo {
public static void main(String[] args) {
//创建 BeanFactory 容器
// DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//将当前类 ObjectProviderDemo 作为配置类
applicationContext.register(TypeSfaetyDependencyLookupDemo.class);
//启动应用上下文
applicationContext.refresh();
// 演示 BeanFactory#getBean 方法的线程安全性(线程不安全,无对象将报错)
displayBeanFactoryGetBean(applicationContext);
// 演示 ObjectFactory#getObject 方法的线程安全性(线程不安全,无对象将报错)
displayObjectFactoryGetObject(applicationContext);
// 演示 ObjectProvider#getIfAvailable 方法的线程安全性(线程安全,无对象不报错)
displayObjectProviderGetIfAvailable(applicationContext);
// 演示 ListableBeanFactory#getBeanOfType 方法的线程安全性(线程安全,无对象不报错)
displayListableBeanFactoryGetBeanOfType(applicationContext);
// 演示 ObjectProvider#Stream 方法的线程安全性(线程安全,无对象不报错)
displayObjectProviderStream(applicationContext);
//关闭应用上下文
applicationContext.close();
}
private static void displayObjectProviderStream(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
printBeansExecption("displayObjectProviderStream", () -> userObjectProvider.forEach(System.out::println));
}
private static void displayListableBeanFactoryGetBeanOfType(ListableBeanFactory beanFactory) {
printBeansExecption("displayListableBeanFactoryGetBeanOfType", () -> beanFactory.getBeansOfType(User.class));
}
private static void displayObjectProviderGetIfAvailable(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
printBeansExecption("displayObjectProviderGetIfAvailable", () -> userObjectProvider.getIfAvailable());
}
private static void displayObjectFactoryGetObject(AnnotationConfigApplicationContext applicationContext) {
ObjectFactory<User> userObjectFactory = applicationContext.getBeanProvider(User.class);
printBeansExecption("displayObjectFactoryGetObject", () -> userObjectFactory.getObject());
}
private static void displayBeanFactoryGetBean(BeanFactory beanFactory) {
printBeansExecption("displayBeanFactoryGetBean", () -> beanFactory.getBean(User.class));
}
private static void printBeansExecption(String source, Runnable runnable) {
System.out.println("====================================");
System.out.println("Source from : " + source);
try {
runnable.run();
} catch (BeansException exception) {
exception.printStackTrace();
}
}
}
运行结果
应用实例14
应用实例14,主讲bean获取时可能会遇到的异常:
1、Bean对象不唯一;
2、Bean对象定义失败;
3、Bean对象创建失败;
代码架构
NoUniqueBeanDefinitionExceptionDemo.java 类定义不唯一
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package springtest.dependency.lookup;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
/**
* {@link NoUniqueBeanDefinitionException} 示例代码
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since
*/
public class NoUniqueBeanDefinitionExceptionDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将当前类 NoUniqueBeanDefinitionExceptionDemo 作为配置类(Configuration Class)
applicationContext.register(NoUniqueBeanDefinitionExceptionDemo.class);
// 启动应用上下文
applicationContext.refresh();
try {
// 由于 Spring 应用上下文存在两个 String 类型的 Bean,通过单一类型查找会抛出异常
applicationContext.getBean(String.class);
} catch (NoUniqueBeanDefinitionException e) {
System.err.printf(" Spring 应用上下文存在%d个 %s 类型的 Bean,具体原因:%s%n",
e.getNumberOfBeansFound(),
String.class.getName(),
e.getMessage());
}
// 关闭应用上下文
applicationContext.close();
}
@Bean
public String bean1() {
return "1";
}
@Bean
public String bean2() {
return "2";
}
@Bean
public String bean3() {
return "3";
}
}
运行结果:
BeanInstantiationExceptionDemo 类实例化异常
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package springtest.dependency.lookup;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* {@link BeanInstantiationException} 实例
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since
*/
public class BeanInstantiationExceptionDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 BeanDefinition Bean Class 是一个 CharSequence 接口
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(CharSequence.class);
applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition());
// 启动应用上下文
applicationContext.refresh();
// 关闭应用上下文
applicationContext.close();
}
}
运行结果:
BeanCreationExceptionDemo 类创建异常
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package springtest.dependency.lookup;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.annotation.PostConstruct;
/**
* {@link BeanCreationException} 示例
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since
*/
public class BeanCreationExceptionDemo {
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 BeanDefinition Bean Class 是一个 POJO 普通类,不过初始化方法回调时抛出异常
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(POJO.class);
applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition());
// 启动应用上下文
applicationContext.refresh();
// 关闭应用上下文
applicationContext.close();
}
static class POJO implements InitializingBean {
@PostConstruct // CommonAnnotationBeanPostProcessor
public void init() throws Throwable {
throw new Throwable("init() : For purposes...");
}
@Override
public void afterPropertiesSet() throws Exception {
throw new Exception("afterPropertiesSet() : For purposes...");
}
}
}
运行结果:
1)只看afterPropertiesSet
2)只看PostConstruct
应用实例15
应用实例15,主讲获取bean对象的3种手动setter方法和2种自动方法:
1、XML-ref方法;
2、构造函数(@Bean);
3、api方法;
4、XML-Autowire方法。
代码架构
pom文件
<?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">
<parent>
<artifactId>springtest</artifactId>
<groupId>springtest</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dependency-injection</artifactId>
<dependencies>
<!-- Spring IoC 核心模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- 复用 ioc-container-overview</artifactId> -->
<dependency>
<groupId>${groupId}</groupId>
<artifactId>ioc-container-overview</artifactId>
<version>${version}</version>
</dependency>
</dependencies>
</project>
UserHolder.java
package spring.ioc.dependency.injection;
import springtest.ioc.overview.domain.User;
/**
* User 的 Holder 类
*/
public class UserHolder {
private User user;
public UserHolder() {
}
public UserHolder(User user) {
this.user = user;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "UserHolder{" +
"user=" + user +
'}';
}
}
通过该类实现bean类演示
XML-ref 实现bean配置
xml配置文件dependency-setter-injection.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/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">
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<bean class="spring.ioc.dependency.injection.UserHolder">
<property name="user" ref="superUser"/>
</bean>
</beans>
1、通过import引用之前的xml配置文件内容;
2、定义bean UserHolder,并在属性配置中,使用“ref”实现类的注入(引用);
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
/**
* 基于 XML 资源的依赖 setter 方法注入
*/
public class XmlDependencySetterInjectionDemo {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String xmlResourcePath = "classpath:/META-INF/dependency-setter-injection.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//依赖查找并且创建 Bean
UserHolder userHolder = beanFactory.getBean(UserHolder.class);
System.out.println(userHolder);
}
}
通过getBean获取UserHolder的bean对象。在获取时通过setter方法将superUser对象赋值给user成员变量。
运行结果
构造函数(@Bean) 实现bean配置
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import springtest.ioc.overview.domain.User;
/**
* 基于 XML 资源的依赖 setter 方法注入
*/
public class AnnotationDependencySetterInjectionDemo {
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类)
applicationContext.register(AnnotationDependencySetterInjectionDemo.class);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动应用上下文
applicationContext.refresh();
//依赖查找并且创建 Bean
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
//关闭应用上下文
applicationContext.close();
}
@Bean
public UserHolder userHolder(User user){
UserHolder userHolder = new UserHolder();
userHolder.setUser(user);
return userHolder;
// return new UserHolder(user);
}
}
通过@Bean注解定义bean,并通过构造函数或setter获得对象。
运行结果
api方法 实现bean配置
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import springtest.ioc.overview.domain.User;
/**
* 基于 API 注解的依赖 setter 方法注入
*/
public class ApiDependencySetterInjectionDemo {
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 UserHolder 的 BeanDefinition
BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
//生成 UserHolder 的 BeanDefinition
applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动应用上下文
applicationContext.refresh();
//依赖查找并且创建 Bean
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
//关闭应用上下文
applicationContext.close();
}
/**
* 为 {@Link UserHolder} 生成 {@Link BeanDefinition}
* @return
*/
private static BeanDefinition createUserHolderBeanDefinition() {
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
definitionBuilder.addPropertyReference("user", "superUser");
return definitionBuilder.getBeanDefinition();
}
// @Bean
// public UserHolder userHolder(User user){ // superUser -> primary = true
// UserHolder userHolder = new UserHolder();
// userHolder.setUser(user);
// return userHolder;
return new UserHolder(user);
// }
}
1、通过definitionBuilder.addPropertyReference(“user”, “superUser”);将类成员变量和xml配置文件中的bean关联。
运行结果
XML-Autowire方法 实现Bean配置
<?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/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">
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<!-- <bean class="spring.ioc.dependency.injection.UserHolder" autowire="byName">-->
<bean class="spring.ioc.dependency.injection.UserHolder" autowire="byType">
<!-- <property name="user" ref="superUser"/> 替换成 autowiring 模式-->
</bean>
</beans>
通过配置文件 autowiring-dependency-setter-injection.xml 中的bean定义,采用 autowire=“byName”/"byType"实现自动绑定。
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
/**
* ByName Autowiring 依赖 Setter 方法注入示例
*/
public class AutoWiringByNameDependencySetterInjectionDemo {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String xmlResourcePath = "classpath:/META-INF/autowiring-dependency-setter-injection.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//依赖查找并且创建 Bean
UserHolder userHolder = beanFactory.getBean(UserHolder.class);
System.out.println(userHolder);
}
}
直接getBean()获取即可。
运行结果
应用实例16
应用实例16延续应用实例15,主讲获取bean对象的3种手动constructor方法和2种自动方法:
1、XML-constructor-arg-ref方法;
2、构造函数(@Bean);
3、api方法;
4、XML-Autowire方法。
代码架构
XML-constructor-arg-ref 实现bean配置
xml配置文件dependency-constructor-injection.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/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">
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<bean class="spring.ioc.dependency.injection.UserHolder">
<constructor-arg name="user" ref="superUser"/>
</bean>
</beans>
1、通过import引用之前的xml配置文件内容;
2、定义bean UserHolder,并在属性配置中,使用“constructor-arg + ref”实现类的注入(引用);
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
/**
* 基于 XML 资源的依赖 constructor 方法注入
*/
public class XmlDependencyConstructorInjectionDemo {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String xmlResourcePath = "classpath:/META-INF/dependency-constructor-injection.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//依赖查找并且创建 Bean
UserHolder userHolder = beanFactory.getBean(UserHolder.class);
System.out.println(userHolder);
}
}
通过getBean获取UserHolder的bean对象。在获取时通过setter方法将superUser对象赋值给user成员变量。
运行结果
构造函数(@Bean) 实现bean配置
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import springtest.ioc.overview.domain.User;
/**
* 基于 XML 资源的依赖 constructor 方法注入
*/
public class AnnotationDependencyConstructorInjectionDemo {
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类)
applicationContext.register(AnnotationDependencyConstructorInjectionDemo.class);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动应用上下文
applicationContext.refresh();
//依赖查找并且创建 Bean
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
//关闭应用上下文
applicationContext.close();
}
@Bean
public UserHolder userHolder(User user){
return new UserHolder(user);
}
}
通过@Bean注解定义bean,并通过构造函数或setter获得对象。
运行结果
api方法 实现bean配置
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 基于 API 注解的依赖 constructor 方法注入
*/
public class ApiDependencyConstructorInjectionDemo {
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 UserHolder 的 BeanDefinition
BeanDefinition userHolderBeanDefinition = createUserHolderBeanDefinition();
//生成 UserHolder 的 BeanDefinition
applicationContext.registerBeanDefinition("userHolder", userHolderBeanDefinition);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动应用上下文
applicationContext.refresh();
//依赖查找并且创建 Bean
UserHolder userHolder = applicationContext.getBean(UserHolder.class);
System.out.println(userHolder);
//关闭应用上下文
applicationContext.close();
}
/**
* 为 {@Link UserHolder} 生成 {@Link BeanDefinition}
* @return
*/
private static BeanDefinition createUserHolderBeanDefinition() {
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(UserHolder.class);
definitionBuilder.addConstructorArgReference("superUser");
return definitionBuilder.getBeanDefinition();
}
// @Bean
// public UserHolder userHolder(User user){ // superUser -> primary = true
// UserHolder userHolder = new UserHolder();
// userHolder.setUser(user);
// return userHolder;
return new UserHolder(user);
// }
}
1、通过definitionBuilder.addConstructorArgReference(“superUser”);将类成员变量和xml配置文件中的bean关联。
运行结果
XML-Autowire方法 实现Bean配置
<?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/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">
<import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
<!-- <bean class="spring.ioc.dependency.injection.UserHolder" autowire="byName">-->
<bean class="spring.ioc.dependency.injection.UserHolder" autowire="constructor">
<!-- <property name="user" ref="superUser"/> 替换成 autowiring 模式-->
</bean>
</beans>```
通过配置文件 autowiring-dependency-constructor-injection.xml 中的bean定义,采用 autowire="constructor"实现自动绑定。
```java
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
/**
* ByName Autowiring 依赖 Constructor 方法注入示例
*/
public class AutoWiringConstructorDependencyConstructorInjectionDemo {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String xmlResourcePath = "classpath:/META-INF/autowiring-dependency-setter-injection.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//依赖查找并且创建 Bean
UserHolder userHolder = beanFactory.getBean(UserHolder.class);
System.out.println(userHolder);
}
}
直接getBean()获取即可。
运行结果
应用实例17
应用实例17延续应用实例16架构,主讲获取bean对象的2种注解配置方式:
1、@Autowire(通过属性);
2、@Resource (通过属性);
3、@Bean (通过方法。)
代码架构
AnnotationDependencyFieldInjectionDemo
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import springtest.ioc.overview.domain.User;
import javax.annotation.Resource;
/**
* 基于 XML 资源的依赖字段方法注入
*/
public class AnnotationDependencyFieldInjectionDemo {
@Autowired
private UserHolder userHolder; //不接受static字段
@Resource
private UserHolder userholder2;
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类) -> Spring Bean
applicationContext.register(AnnotationDependencyFieldInjectionDemo.class);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动应用上下文
applicationContext.refresh();
//依赖查找 AnnotationDependencyFieldInjectionDemo Bean
AnnotationDependencyFieldInjectionDemo demo = applicationContext.getBean(AnnotationDependencyFieldInjectionDemo.class);
//依赖查找并且创建 Bean
UserHolder userHolder = demo.userHolder;
System.out.println(userHolder);
System.out.println(demo.userholder2);
System.out.println(userHolder == demo.userholder2);
//关闭应用上下文
applicationContext.close();
}
@Bean
public UserHolder userHolder(User user){
return new UserHolder(user);
}
}
通过@Autowire和@Resource实现自注入,然后通过bean类进行提取(按类型)。
运行结果
应用实例18
应用实例18延续应用实例17架构,主讲获取bean对象的2种注解配置方式(通过方法实现):
1、@Autowire(通过方法);
2、@Resource (通过方法);
3、@Bean (通过方法)。
代码架构
AnnotationDependencyMethodInjectionDemo
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import springtest.ioc.overview.domain.User;
import javax.annotation.Resource;
/**
* 基于 XML 资源的依赖字段方法注入
*/
public class AnnotationDependencyMethodInjectionDemo {
private UserHolder userHolder; //不接受static字段
private UserHolder userholder2;
@Autowired
public void initUserHolder(UserHolder userHolder){
this.userHolder = userHolder;
}
@Resource
public void initUserHolder2(UserHolder userHolder2){
this.userholder2 = userHolder2;
}
@Bean
public UserHolder userHolder(User user){
return new UserHolder(user);
}
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类) -> Spring Bean
applicationContext.register(AnnotationDependencyMethodInjectionDemo.class);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动应用上下文
applicationContext.refresh();
//依赖查找 AnnotationDependencyFieldInjectionDemo Bean
AnnotationDependencyMethodInjectionDemo demo = applicationContext.getBean(AnnotationDependencyMethodInjectionDemo.class);
//依赖查找并且创建 Bean
UserHolder userHolder = demo.userHolder;
System.out.println(userHolder);
System.out.println(demo.userholder2);
System.out.println(userHolder == demo.userholder2);
//关闭应用上下文
applicationContext.close();
}
}
通过在类似set方法前配置@Autowire和@Resource,同样可以实现类对象注入。
应用实例19
应用实例19延续应用实例18架构,主讲通过实现BeanFactoryAware和ApplicationContextAware接口完成接口回调注入。
代码架构
AwareInterfaceDependencyInjectionDemo
package spring.ioc.dependency.injection;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
/**
* 基于 Aware 接口回调的依赖注入示例
*/
public class AwareInterfaceDependencyInjectionDemo implements BeanFactoryAware, ApplicationContextAware {
private static BeanFactory beanFactory;
private static ApplicationContext applicationContext;
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类) -> Spring Bean
context.register(AwareInterfaceDependencyInjectionDemo.class);
//启动应用上下文
context.refresh();
System.out.println(beanFactory == context.getBeanFactory());
System.out.println(applicationContext == context);
//关闭应用上下文
context.close();
}
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
AwareInterfaceDependencyInjectionDemo.beanFactory = beanFactory;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
AwareInterfaceDependencyInjectionDemo.applicationContext = applicationContext;
}
}
通过实现BeanFactoryAware和ApplicationContextAware接口的set方法,实现bean对象接口回调。
运行结果
应用实例20
应用实例20主讲枚举类型和资源类型的自动注入。
代码架构
City 枚举类
package springtest.ioc.overview.enums;
/**
* 城市枚举
*/
public enum City {
BEIJING,
SHANGHAI,
GUANGZHOU,
SHENZHEN
}
包含北京、上海、广州和深圳。
User 增加城市和资源属性
package springtest.ioc.overview.domain;
import org.springframework.core.io.Resource;
import springtest.ioc.overview.enums.City;
/**
* 用户类
*/
public class User {
private Long id;
private String name;
private City city;
private Resource configFileLocation;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
public Resource getConfigFileLocation() {
return configFileLocation;
}
public void setConfigFileLocation(Resource configFileLocation) {
this.configFileLocation = configFileLocation;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", city=" + city +
", configFileLocation=" + configFileLocation +
'}';
}
/**
* 静态方法构建 bean
* @return
*/
public static User createUser(){
User user = new User();
user.setId(1L);
user.setName("xiaohhong");
return user;
}
}
dependency-lookup-context.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/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">
<bean id="user" class="springtest.ioc.overview.domain.User">
<property name="id" value="1"/>
<property name="name" value="xiaoming"/>
<property name="city" value="SHENZHEN"/>
<property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
</bean>
<bean id="superUser" class="springtest.ioc.overview.domain.SuperUser" parent="user" primary="true">
<property name="address" value="Hangzhou"/>
</bean>
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
增加 city 和 congifFileLocation配置。
DependencyLookupDemo
package springtest.ioc.overview.dependency.lookup;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.ioc.overview.annotation.Super;
import springtest.ioc.overview.domain.SuperUser;
import springtest.ioc.overview.domain.User;
import java.util.Map;
/**
* 依赖查找示例
* 1、通过名称查找
* 2、通过类型查找
*/
public class DependencyLookupDemo {
public static void main(String[] args) {
//配置 xml 配置文件
//启动 Spring 应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml");
//按照id实时查找
lookupInRealTime(beanFactory);
//按照id延迟查找
lookInLazy(beanFactory);
//按照类型查找
lookupByType(beanFactory);
//按照集合类型查找
lookupByColleactionType(beanFactory);
//通过注解查找
lookupByAnnotationType(beanFactory);
}
public static void lookupInRealTime(BeanFactory beanFactory) {
User user = (User) beanFactory.getBean("user");
System.out.println("实时查找:" + user);
}
private static void lookInLazy(BeanFactory beanFactory) {
ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
User user = objectFactory.getObject();
System.out.println("延迟查找:" + user);
}
private static void lookupByType(BeanFactory beanFactory) {
User user = beanFactory.getBean(User.class);
System.out.println("实时(类型)查找:" + user);
}
private static void lookupByColleactionType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("实时(集合类型)查找:" + users);
}
}
private static void lookupByAnnotationType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println("查找标注@Super的用户集合:" + users);
}
}
}
运行结果
应用实例21
应用实例21承接应用实例20,主讲数组和集合类型注入,通过City数组和集合来举例。
User
package springtest.ioc.overview.domain;
import org.springframework.core.io.Resource;
import springtest.ioc.overview.enums.City;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* 用户类
*/
public class User {
private Long id;
private String name;
private City city;
private City[] workCities;
private List<City> lifeCities;
private Set<City> friendCities;
private Resource configFileLocation;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
public City[] getWorkCities() {
return workCities;
}
public void setWorkCities(City[] workCities) {
this.workCities = workCities;
}
public List<City> getLifeCities() {
return lifeCities;
}
public void setLifeCities(List<City> lifeCities) {
this.lifeCities = lifeCities;
}
public Set<City> getFriendCities() {
return friendCities;
}
public void setFriendCities(Set<City> friendCities) {
this.friendCities = friendCities;
}
public Resource getConfigFileLocation() {
return configFileLocation;
}
public void setConfigFileLocation(Resource configFileLocation) {
this.configFileLocation = configFileLocation;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", city=" + city +
", workCities=" + Arrays.toString(workCities) +
", lifeCities=" + lifeCities +
", friendCities=" + friendCities +
", configFileLocation=" + configFileLocation +
'}';
}
/**
* 静态方法构建 bean
* @return
*/
public static User createUser(){
User user = new User();
user.setId(1L);
user.setName("xiaohhong");
return user;
}
}
workCities是数组类型,lifeCities是List集合,friendCities是Set集合。
dependency-lookup-context.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/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">
<bean id="user" class="springtest.ioc.overview.domain.User">
<property name="id" value="1"/>
<property name="name" value="xiaoming"/>
<property name="city" value="SHENZHEN"/>
<property name="workCities" value="BEIJING, SHANGHAI"/>
<property name="lifeCities" value="SHANGHAI, GUANGZHOU"/>
<property name="friendCities">
<set>
<value>GUANGZHOU</value>
<value>SHENZHEN</value>
</set>
</property>
<property name="configFileLocation" value="classpath:/META-INF/user-config.properties"/>
</bean>
<bean id="superUser" class="springtest.ioc.overview.domain.SuperUser" parent="user" primary="true">
<property name="address" value="Hangzhou"/>
</bean>
<bean id="objectFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
<property name="targetBeanName" value="user"/>
</bean>
</beans>
数组和集合都可以在property中的value上直接用逗号分割就可以表示集合元素,或者在property下增加list或set子节点来注入集合元素。
调试类 DependencyLookupDemo
package springtest.ioc.overview.dependency.lookup;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springtest.ioc.overview.annotation.Super;
import springtest.ioc.overview.domain.SuperUser;
import springtest.ioc.overview.domain.User;
import java.util.Map;
/**
* 依赖查找示例
* 1、通过名称查找
* 2、通过类型查找
*/
public class DependencyLookupDemo {
public static void main(String[] args) {
//配置 xml 配置文件
//启动 Spring 应用上下文
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/dependency-lookup-context.xml");
//按照id实时查找
lookupInRealTime(beanFactory);
//按照id延迟查找
lookInLazy(beanFactory);
//按照类型查找
lookupByType(beanFactory);
//按照集合类型查找
lookupByColleactionType(beanFactory);
//通过注解查找
lookupByAnnotationType(beanFactory);
}
public static void lookupInRealTime(BeanFactory beanFactory) {
User user = (User) beanFactory.getBean("user");
System.out.println("实时查找:" + user);
}
private static void lookInLazy(BeanFactory beanFactory) {
ObjectFactory<User> objectFactory = (ObjectFactory<User>) beanFactory.getBean("objectFactory");
User user = objectFactory.getObject();
System.out.println("延迟查找:" + user);
}
private static void lookupByType(BeanFactory beanFactory) {
User user = beanFactory.getBean(User.class);
System.out.println("实时(类型)查找:" + user);
}
private static void lookupByColleactionType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = listableBeanFactory.getBeansOfType(User.class);
System.out.println("实时(集合类型)查找:" + users);
}
}
private static void lookupByAnnotationType(BeanFactory beanFactory) {
if (beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) beanFactory;
Map<String, User> users = (Map) listableBeanFactory.getBeansWithAnnotation(Super.class);
System.out.println("查找标注@Super的用户集合:" + users);
}
}
}
运行结果
应用实例22
应用实例22继承应用实例21,主讲通过@Autowire、@Qualifier和继承自@Qualifier注解的注入和使用。
代码架构
@UserGroup
package spring.ioc.dependency.injection.annotation;
import org.springframework.beans.factory.annotation.Qualifier;
import java.lang.annotation.*;
/**
* 用户组注解,扩展 @Qualifier
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier
public @interface UserGroup {
}
@UserGroup开头的定义直接拷贝自@Qualifier,同时在前面也增加了@Qualifier,表示@UserGroup继承了@Qualifier特性。
QualifierAnnotationDependencyInjectionDemo
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import spring.ioc.dependency.injection.annotation.UserGroup;
import springtest.ioc.overview.domain.User;
import java.util.Collection;
/**
* Qualifier 注解依赖注入
*/
public class QualifierAnnotationDependencyInjectionDemo {
@Autowired
private User user; //SuperUser
@Autowired
@Qualifier("user") //指定 Bean 的名称或 ID
private User namedUser;
//整体应用上下文存在 4个 User 类型的 Bean
//superUser
//user
//user1 -> @Qualifier
//user2 -> @Qualifier
@Autowired
private Collection<User> allUsers; //2 Bean -> user + superUser
@Autowired
@Qualifier
private Collection<User> qualifierUsers; //2 Bean -> user1 + user2 + user3 + user4
@Autowired
@UserGroup
private Collection<User> userGroupUsers; //2 Bean -> user3 + user4
@Bean
@Qualifier
public User user1() {
return createUser(7L);
}
@Bean
@Qualifier
public User user2() {
return createUser(8L);
}
@Bean
@UserGroup
public User user3() {
return createUser(9L);
}
@Bean
@UserGroup
public User user4() {
return createUser(10L);
}
private static User createUser(Long id) {
User user = new User();
user.setId(id);
return user;
}
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类) -> Spring Bean
applicationContext.register(QualifierAnnotationDependencyInjectionDemo.class);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动应用上下文
applicationContext.refresh();
//依赖查找 AnnotationDependencyFieldInjectionDemo Bean
QualifierAnnotationDependencyInjectionDemo demo = applicationContext.getBean(QualifierAnnotationDependencyInjectionDemo.class);
//输出 superUser Bean
System.out.println("demo.user = " + demo.user);
//输出 user Bean
System.out.println("demo.nanmedUser = " + demo.namedUser);
//输出 allUsers Bean
System.out.println("demo.allUsers = " + demo.allUsers);
//输出 qualifierUsers Bean
System.out.println("demo.qualifierUsers = " + demo.qualifierUsers);
//输出 userGroupUsers Bean
System.out.println("demo.userGroupUsers = " + demo.userGroupUsers);
//关闭应用上下文
applicationContext.close();
}
}
可以看出:
1、@Autowire 可以自动注入类型,只是注入的是最高优先级;
2、@Autowire 和 @Qualifier一起使用,并在@Qualifier中指定需要注入的Bean id;
3、在注入集合时,@Autowire 会将相同类型的、并且没有标注其他注解的Bean全部注入结合中(不包括使用了@Qualifier 和 @UserGroup的bean);
4、在注入集合时,@Autowire 和 @Qualifier一起使用,会将相同类型的、并且标注了@Qualifier的Bean全部注入结合中(包括使用了@UserGroup的bean);
5、在注入集合时,@Autowire 和 @UserGroup一起使用,会将相同类型的、并且标注了@UserGroup的Bean全部注入结合中(不包括使用了@Qualifier的bean);
运行结果
demo.user = SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.nanmedUser = User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.allUsers = [User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}, SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}]
demo.qualifierUsers = [User{id=7, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}, User{id=8, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}, User{id=9, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}, User{id=10, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}]
demo.userGroupUsers = [User{id=9, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}, User{id=10, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}]
Process finished with exit code 0
应用实例23
应用实例23继承应用实例22,主讲通过ObjectProvider实现延迟注入。
代码架构
LazyAnnotationDependencyInjectionDemo
package spring.ioc.dependency.injection;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import spring.ioc.dependency.injection.annotation.UserGroup;
import springtest.ioc.overview.domain.User;
import java.util.Collection;
import java.util.Set;
/**
* Qualifier 注解依赖注入
*/
public class LazyAnnotationDependencyInjectionDemo {
@Autowired
private User user; //SuperUser
@Autowired
private ObjectProvider<User> objectProvider; //如果有多个对象,不会报错
@Autowired
private ObjectFactory<Set<User>> objectFactory; //如果有多个对象,会报错
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类) -> Spring Bean
applicationContext.register(LazyAnnotationDependencyInjectionDemo.class);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动应用上下文
applicationContext.refresh();
//依赖查找 AnnotationDependencyFieldInjectionDemo Bean
LazyAnnotationDependencyInjectionDemo demo = applicationContext.getBean(LazyAnnotationDependencyInjectionDemo.class);
//输出 superUser Bean
System.out.println("demo.user = " + demo.user);
//输出 user Bean
System.out.println("demo.objectProvider = " + demo.objectProvider.getObject());
demo.objectProvider.forEach(System.out::println);
//输出 user Bean
System.out.println("demo.objectFactory = " + demo.objectFactory.getObject());
//关闭应用上下文
applicationContext.close();
}
}
运行结果
demo.user = SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.objectProvider = SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.objectFactory = [User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}, SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}]
Process finished with exit code 0
应用实例24
应用实例24继承应用实例23,主讲实现延迟注入的原发分析。
代码架构
AnnotationDependencyInjectionResolutionDemo
package spring.ioc.dependency.injection;
import com.oracle.tools.packager.mac.MacAppBundler;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import springtest.ioc.overview.domain.User;
import javax.inject.Inject;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
/**
* 注解依赖驱动的注入处理过程
*/
public class AnnotationDependencyInjectionResolutionDemo {
@Autowired // 依赖查找(处理)
private User user; // DependencyDescriptor ->
// 必须(required=true)
// 实时注入(eager=true)
// 通过类型(User.class)
// 字段名称("user")
// 是否 (primary=true)
@Autowired // 集合类型的依赖注入
private Map<String, User> users; //user superUser
@Autowired
private Optional<User> optionalUser; //user
@Inject
private User injectUser;
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类) -> Spring Bean
applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动应用上下文
applicationContext.refresh();
//依赖查找 AnnotationDependencyFieldInjectionDemo Bean
AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);
//输出 superUser Bean
System.out.println("demo.user = " + demo.user);
System.out.println("demo.injectUser = " + demo.injectUser);
//输出 user Bean
System.out.println("demo.user = " + demo.users);
//输出 superUser Bean
System.out.println("demo.optionalUser = " + demo.optionalUser);
//关闭应用上下文
applicationContext.close();
}
}
运行结果
demo.user = SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.injectUser = SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}
demo.user = {user=User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}, superUser=SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}}
demo.optionalUser = Optional[SuperUser{address='Hangzhou'} User{id=1, name='xiaoming', city=SHENZHEN, workCities=[BEIJING, SHANGHAI], lifeCities=[SHANGHAI, GUANGZHOU], friendCities=[GUANGZHOU, SHENZHEN], configFileLocation=class path resource [META-INF/user-config.properties]}]
Process finished with exit code 0
应用实例25
应用实例25主讲实现自定义依赖注入的方法。
代码架构
MyAutowired注解
package spring.ioc.dependency.injection.annotation;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.annotation.*;
/**
* 自定义注解(元标注 @Autowired)
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Autowired
public @interface MyAutowired {
boolean required() default true;
}
@MyAutowired主要继承Autowired,作用和@Autowired一样。
InjectedUser注解
package spring.ioc.dependency.injection.annotation;
import java.lang.annotation.*;
/**
* 自定义依赖注入注解
*/
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InjectedUser {
}
@InjectedUser注解直接赋值@Injected,作用相同。
AnnotationDependencyInjectionResolutionDemo
package spring.ioc.dependency.injection;
import com.oracle.tools.packager.mac.MacAppBundler;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import spring.ioc.dependency.injection.annotation.InjectedUser;
import spring.ioc.dependency.injection.annotation.MyAutowired;
import springtest.ioc.overview.domain.User;
import javax.inject.Inject;
import java.lang.annotation.Annotation;
import java.util.*;
import static java.util.Arrays.asList;
import static org.springframework.context.annotation.AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME;
/**
* 注解依赖驱动的注入处理过程
*/
public class AnnotationDependencyInjectionResolutionDemo {
@Autowired // 依赖查找(处理)
private User user; // DependencyDescriptor ->
// 必须(required=true)
// 实时注入(eager=true)
// 通过类型(User.class)
// 字段名称("user")
// 是否 (primary=true)
@Autowired // 集合类型的依赖注入
private Map<String, User> users; //user superUser
@MyAutowired
private Optional<User> optionalUser; //user
@Inject
private User injectUser;
@InjectedUser
private User myInjectedUser;
//方法一
// @Bean(name = AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)
// public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
// AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
// // @Autowired + @Inject + 新注解 @InjectedUser
// Set<Class<? extends Annotation>> autowiredAnnotationTypes =
// new LinkedHashSet<>(asList(Autowired.class, Inject.class, InjectedUser.class));
// beanPostProcessor.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
// return beanPostProcessor;
// }
//方法二
@Bean()
@Order(Ordered.LOWEST_PRECEDENCE - 3)
public static AutowiredAnnotationBeanPostProcessor beanPostProcessor() {
AutowiredAnnotationBeanPostProcessor beanPostProcessor = new AutowiredAnnotationBeanPostProcessor();
beanPostProcessor.setAutowiredAnnotationType(InjectedUser.class);
return beanPostProcessor;
}
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类) -> Spring Bean
applicationContext.register(AnnotationDependencyInjectionResolutionDemo.class);
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
String xmlResourcePath = "classpath:/META-INF/dependency-lookup-context.xml";
// 加载 XML 资源,解析并生成 BeanDefinition
beanDefinitionReader.loadBeanDefinitions(xmlResourcePath);
//启动应用上下文
applicationContext.refresh();
//依赖查找 AnnotationDependencyFieldInjectionDemo Bean
AnnotationDependencyInjectionResolutionDemo demo = applicationContext.getBean(AnnotationDependencyInjectionResolutionDemo.class);
//输出 superUser Bean
System.out.println("demo.user = " + demo.user);
System.out.println("demo.injectUser = " + demo.injectUser);
//输出 user Bean
System.out.println("demo.user = " + demo.users);
//输出 superUser Bean
System.out.println("demo.optionalUser = " + demo.optionalUser);
//输出 superUser Bean
System.out.println("demo.myInjectedUser = " + demo.myInjectedUser);
//关闭应用上下文
applicationContext.close();
}
}
两种方法实现依赖注入:一种是通过组合将3个注释加入对象中,这样3个对象都可执行依赖注入;另一种只注入@InjectUser来实现依赖注入,通过增加@order来指定执行顺序(定义Spring IOC容器中Bean的执行顺序的优先级,而不是定义Bean的加载顺序)。
应用实例26
应用实例26主讲依赖注入和依赖查找在来源上的查边:依赖注入比依赖查找多一个非Spring管理机构。
代码架构
pom
<?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">
<parent>
<artifactId>springtest</artifactId>
<groupId>springtest</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dependency-source</artifactId>
<dependencies>
<!-- Spring IoC 核心模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- 复用 ioc-container-overview</artifactId> -->
<dependency>
<groupId>${groupId}</groupId>
<artifactId>ioc-container-overview</artifactId>
<version>${version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
源代码中关于4个类型的依赖注入操作
DependencySourceDemo
package springtest.dependency.source;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.core.io.ResourceLoader;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* 依赖来源示例
*/
public class DependencySourceDemo {
/**
* 注入在 postProcessProperties 方法执行,早于 setter 注入,也早于@PostConstruct
*/
@Autowired
private BeanFactory beanFactory;
@Autowired
private ResourceLoader resourceLoader;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
//依赖注入比依赖查找多一项
@PostConstruct
public void initByInjection() {
System.out.println("beanFactory == applicationContext:" + (beanFactory == applicationContext));
System.out.println("beanFactory == applicationContext.getAutowireCapableBeanFactory():" + (beanFactory == applicationContext.getAutowireCapableBeanFactory()));
System.out.println("resourceLoader == applicationContext:" + (resourceLoader == applicationContext));
System.out.println("applicationEventPublisher == applicationContext:" + (applicationEventPublisher == applicationContext));
}
@PostConstruct
public void initByLookup() {
getBean(BeanFactory.class);
getBean(ResourceLoader.class);
getBean(ApplicationContext.class);
getBean(ApplicationEventPublisher.class);
}
private <T> T getBean(Class<T> beanType) {
try {
return beanFactory.getBean(beanType);
} catch (NoSuchBeanDefinitionException e) {
System.out.println("当前类型:" + beanType.getName() + "无法在BeanFactory中找到。");
}
return null;
}
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类) -> Spring Bean
applicationContext.register(DependencySourceDemo.class);
//启动应用上下文
applicationContext.refresh();
//依赖查找 DependencySourceDemo Bean
DependencySourceDemo demo = applicationContext.getBean(DependencySourceDemo.class);
//关闭应用上下文
applicationContext.close();
}
}
运行结果
应用实例27
应用实例27主讲通过配置文件实现依赖注入。
代码架构
配置文件 default.properties
user.id = 1
usr.name = 小马哥
user.resource = classpath:/META-INF/default.properties
ExternalConfigurationDependencySourceDemo
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package springtest.dependency.source;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;
/**
* 外部化配置作为依赖来源示例
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since
*/
@Configuration
@PropertySource(value = "classpath:/META-INF/default.properties", encoding = "UTF-8")
public class ExternalConfigurationDependencySourceDemo {
@Value("${user.id:-1}")
private Long id;
@Value("${usr.name}")
private String name;
@Value("${user.resource:classpath:/default.properties}")
private Resource resource;
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration Class(配置类) -> Spring Bean
applicationContext.register(ExternalConfigurationDependencySourceDemo.class);
// 启动 Spring 应用上下文
applicationContext.refresh();
// 依赖查找 ExternalConfigurationDependencySourceDemo Bean
ExternalConfigurationDependencySourceDemo demo = applicationContext.getBean(ExternalConfigurationDependencySourceDemo.class);
System.out.println("demo.id = " + demo.id);
System.out.println("demo.name = " + demo.name);
System.out.println("demo.resource = " + demo.resource);
// 显示地关闭 Spring 应用上下文
applicationContext.close();
}
}
应用实例28
应用实例28主讲singleton和prototype的有效范围。
代码架构
pom
<?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">
<parent>
<artifactId>springtest</artifactId>
<groupId>springtest</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bean-scope</artifactId>
<dependencies>
<!-- Spring IoC 核心模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- 复用 ioc-container-overview</artifactId> -->
<dependency>
<groupId>${groupId}</groupId>
<artifactId>ioc-container-overview</artifactId>
<version>${version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
复用之前的代码配置。
User定义
package springtest.ioc.overview.domain;
import jdk.nashorn.internal.objects.annotations.Constructor;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.core.io.Resource;
import springtest.ioc.overview.enums.City;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* 用户类
*/
public class User implements BeanNameAware {
private Long id;
private String name;
private City city;
private City[] workCities;
private List<City> lifeCities;
private Set<City> friendCities;
private Resource configFileLocation;
/**
* 当前 Bean 的名称
*/
private transient String beanName;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
public City[] getWorkCities() {
return workCities;
}
public void setWorkCities(City[] workCities) {
this.workCities = workCities;
}
public List<City> getLifeCities() {
return lifeCities;
}
public void setLifeCities(List<City> lifeCities) {
this.lifeCities = lifeCities;
}
public Set<City> getFriendCities() {
return friendCities;
}
public void setFriendCities(Set<City> friendCities) {
this.friendCities = friendCities;
}
public Resource getConfigFileLocation() {
return configFileLocation;
}
public void setConfigFileLocation(Resource configFileLocation) {
this.configFileLocation = configFileLocation;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", city=" + city +
", workCities=" + Arrays.toString(workCities) +
", lifeCities=" + lifeCities +
", friendCities=" + friendCities +
", configFileLocation=" + configFileLocation +
'}';
}
/**
* 静态方法构建 bean
* @return
*/
public static User createUser(){
User user = new User();
user.setId(1L);
user.setName("xiaohhong");
return user;
}
@PostConstruct
public void init(){
System.out.println("beanName:" + beanName + ",用户对象初始化...");
}
@PreDestroy
public void destroy(){
System.out.println("beanName:" + beanName + ",用户对象销毁...");
}
@Override
public void setBeanName(String s) {
this.beanName = s;
}
}
其中:
1、BeanNameAware接口主要用来设置beanName,这里需要自行定义一个beanName对象。代码中在定义beanName的时候在前面增加了transient,表示这个属性不会进行序列化;
2、@PostContruct和@PreDestroy注解分别表示初始化和销毁,此处主要用于打印bean初始化和销毁的时间点,方便理解;
BeanScopeDemo
package springtest.bean.scope;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.ResourceLoader;
import springtest.ioc.overview.domain.User;
import javax.annotation.PostConstruct;
import java.util.Map;
/**
* 依赖来源示例
*/
public class BeanScopeDemo implements DisposableBean {
@Bean
// 默认 scope 就是 singletion
public static User singletonUser(){
return createUser();
}
@Bean
// @Scope("prototype")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public static User prototypeUser(){
return createUser();
}
private static User createUser(){
User user = new User();
user.setId(System.nanoTime());
return user;
}
@Autowired
@Qualifier("singletonUser")
private User singletonUser;
@Autowired
@Qualifier("singletonUser")
private User singletonUser1;
@Autowired
@Qualifier("prototypeUser")
private User prototypeUser;
@Autowired
@Qualifier("prototypeUser")
private User prototypeUser1;
@Autowired
@Qualifier("prototypeUser")
private User prototypeUser2;
@Autowired
private Map<String, User> users;
@Autowired
private ConfigurableListableBeanFactory beanFactory; // Resolvable Dependency
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类) -> Spring Bean
applicationContext.register(BeanScopeDemo.class);
applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.printf("%s Bean 名称:%s 在初始化后回调...%n", bean.getClass().getName(), beanName);
return bean;
}
});
});
//启动应用上下文
applicationContext.refresh();
//结论一:
//singleton Bean 无论是依赖查找还是注入,均为同一个对象
//prototype Bean 无论是依赖查找还是注入,均生成新的对象
//结论二:
//如果依赖注入集合型对象时,singleton Bean和prototype Bean均只存在一份
//prototype Bean有别于其他地方的依赖注入prototype Bean
// 结论三:
// 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
// 不过仅 Singleton Bean 会执行销毁方法回调
scopeBeanByLookip(applicationContext);
scopeBeanByInjection(applicationContext);
//关闭应用上下文
applicationContext.close();
}
private static void scopeBeanByLookip(AnnotationConfigApplicationContext applicationContext) {
for (int i = 0; i < 3; i++) {
// singleton 是共享型 bean 对象
User singleton = applicationContext.getBean("singletonUser", User.class);
System.out.println("singletonUser = " + singleton);
// prototype 是独享型 bean 对象
User prototype = applicationContext.getBean("prototypeUser", User.class);
System.out.println("prototypeUser = " + prototype);
}
}
private static void scopeBeanByInjection(AnnotationConfigApplicationContext applicationContext) {
BeanScopeDemo beanScopeDemo = applicationContext.getBean(BeanScopeDemo.class);
System.out.println("beanScopeDemo.singletonUser = " + beanScopeDemo.singletonUser);
System.out.println("beanScopeDemo.singletonUser1 = " + beanScopeDemo.singletonUser1);
System.out.println("beanScopeDemo.prototypeUser = " + beanScopeDemo.prototypeUser);
System.out.println("beanScopeDemo.prototypeUser1 = " + beanScopeDemo.prototypeUser1);
System.out.println("beanScopeDemo.prototypeUser2 = " + beanScopeDemo.prototypeUser2);
System.out.println("beanScopeDemo.users = " + beanScopeDemo.users);
}
@Override
public void destroy() throws Exception {
System.out.println("当前 BeanScopeDemo Bean 正在销毁中...");
this.prototypeUser.destroy();
this.prototypeUser1.destroy();
this.prototypeUser1.destroy();
this.prototypeUser2.destroy();
// 获取 BeanDefinition
for (Map.Entry<String, User> entry : this.users.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (beanDefinition.isPrototype()) { // 如果当前 Bean 是 prototype scope
User user = entry.getValue();
user.destroy();
}
}
System.out.println("当前 BeanScopeDemo Bean 销毁完成");
}
}
结论:
结论一:
singleton Bean 无论是依赖查找还是注入,均为同一个对象
prototype Bean 无论是依赖查找还是注入,均生成新的对象
结论二:
如果依赖注入集合型对象时,singleton Bean和prototype Bean均只存在一份
prototype Bean有别于其他地方的依赖注入prototype Bean
结论三:
无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
不过仅 Singleton Bean 会执行销毁方法回调
其中:
1、DisposableBean用于对象类销毁时的操作,实现destroy方法。
运行结果
org.springframework.context.event.EventListenerMethodProcessor Bean 名称:org.springframework.context.event.internalEventListenerProcessor 在初始化后回调...
org.springframework.context.event.DefaultEventListenerFactory Bean 名称:org.springframework.context.event.internalEventListenerFactory 在初始化后回调...
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor Bean 名称:org.springframework.context.annotation.internalAutowiredAnnotationProcessor 在初始化后回调...
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor Bean 名称:org.springframework.context.annotation.internalCommonAnnotationProcessor 在初始化后回调...
beanName:singletonUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:singletonUser 在初始化后回调...
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
springtest.bean.scope.BeanScopeDemo Bean 名称:beanScopeDemo 在初始化后回调...
singletonUser = User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
prototypeUser = User{id=594157593713595, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
singletonUser = User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
prototypeUser = User{id=594157596412233, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
singletonUser = User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanName:prototypeUser,用户对象初始化...
springtest.ioc.overview.domain.User Bean 名称:prototypeUser 在初始化后回调...
prototypeUser = User{id=594157597510228, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.singletonUser = User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.singletonUser1 = User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.prototypeUser = User{id=594157537496854, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.prototypeUser1 = User{id=594157543965313, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.prototypeUser2 = User{id=594157547245936, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}
beanScopeDemo.users = {singletonUser=User{id=594157514189459, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}, prototypeUser=User{id=594157559292355, name='null', city=null, workCities=null, lifeCities=null, friendCities=null, configFileLocation=null}}
当前 BeanScopeDemo Bean 正在销毁中...
beanName:prototypeUser,用户对象销毁...
beanName:prototypeUser,用户对象销毁...
beanName:prototypeUser,用户对象销毁...
beanName:prototypeUser,用户对象销毁...
beanName:prototypeUser,用户对象销毁...
当前 BeanScopeDemo Bean 销毁完成
beanName:singletonUser,用户对象销毁...
Process finished with exit code 0
应用实例29
应用实例29主讲scope。
代码架构
pom
<?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">
<parent>
<artifactId>springtest</artifactId>
<groupId>springtest</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>bean-scope</artifactId>
<packaging>war</packaging>
<dependencies>
<!-- Spring IoC 核心模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- 复用 ioc-container-overview</artifactId> -->
<dependency>
<groupId>${groupId}</groupId>
<artifactId>ioc-container-overview</artifactId>
<version>${version}</version>
</dependency>
<!-- 使用 Servlet 3.1 API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<version>2.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>2.2.0.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Tomcat 8 Maven 插件用于构建可执行 war -->
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.maven/tomcat8-maven-plugin -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat8-maven-plugin</artifactId>
<version>3.0-r1655215</version>
<executions>
<execution>
<id>tomcat-run</id>
<goals>
<!-- 最终打包成可执行的jar包 -->
<goal>exec-war-only</goal>
</goals>
<phase>package</phase>
<configuration>
<!-- ServletContext 路径 -->
<path>/</path>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<!-- tomcat8-maven-plugin 所在仓库 -->
<id>Alfresco</id>
<name>Alfresco Repository</name>
<url>https://artifacts.alfresco.com/nexus/content/repositories/public/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
dispatch-servlet.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/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">
<!-- 激活 Spring 注解驱动 -->
<context:component-scan base-package="springtest.bean.scope"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
index.jsp
<?xml version="1.0" encoding="UTF-8" ?>
<jsp:directive.page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" />
<html>
<head>
<link rel="stylesheet" href="<spring:theme code='styleSheet'/>" type="text/css"/>
</head>
<body>
\${userObject.name} : ${userObject.name}
\${applicationScope['scopedTarget.user'].name} : ${applicationScope['scopedTarget.user'].name}
</body>
</html>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
WebConfiguration
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package springtest.bean.scope.web;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.annotation.ApplicationScope;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import springtest.ioc.overview.domain.User;
/**
* Web MVC 配置类
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since
*/
@Configuration
@EnableWebMvc
public class WebConfiguration {
@Bean
// @RequestScope
// @SessionScope
@ApplicationScope
public User user() {
User user = new User();
user.setId(1L);
user.setName("小马哥");
return user;
}
}
IndexController
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package springtest.bean.scope.web.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import springtest.ioc.overview.domain.User;
/**
* 首页 Spring Web MVC Controller
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since
*/
@Controller
public class IndexController {
@Autowired
private User user; // CGLIB 代理后对象(不变的)
@GetMapping("/index.html")
public String index(Model model) {
// JSP EL 变量搜索路径 page -> request -> session -> application(ServletContext)
// userObject -> 渲染上下文
// user 对象存在 ServletContext,上下文名称:scopedTarget.user == 新生成 Bean 名称
model.addAttribute("userObject", user);
return "index";
}
}
BeanScopeDemo
package springtest.bean.scope;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.core.io.ResourceLoader;
import springtest.ioc.overview.domain.User;
import javax.annotation.PostConstruct;
import java.util.Map;
/**
* 依赖来源示例
*/
public class BeanScopeDemo implements DisposableBean {
@Bean
// 默认 scope 就是 singletion
public static User singletonUser(){
return createUser();
}
@Bean
// @Scope("prototype")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public static User prototypeUser(){
return createUser();
}
private static User createUser(){
User user = new User();
user.setId(System.nanoTime());
return user;
}
@Autowired
@Qualifier("singletonUser")
private User singletonUser;
@Autowired
@Qualifier("singletonUser")
private User singletonUser1;
@Autowired
@Qualifier("prototypeUser")
private User prototypeUser;
@Autowired
@Qualifier("prototypeUser")
private User prototypeUser1;
@Autowired
@Qualifier("prototypeUser")
private User prototypeUser2;
@Autowired
private Map<String, User> users;
@Autowired
private ConfigurableListableBeanFactory beanFactory; // Resolvable Dependency
public static void main(String[] args) {
//创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//注册 Configuration Class (配置类) -> Spring Bean
applicationContext.register(BeanScopeDemo.class);
applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.printf("%s Bean 名称:%s 在初始化后回调...%n", bean.getClass().getName(), beanName);
return bean;
}
});
});
//启动应用上下文
applicationContext.refresh();
//结论一:
//singleton Bean 无论是依赖查找还是注入,均为同一个对象
//prototype Bean 无论是依赖查找还是注入,均生成新的对象
//结论二:
//如果依赖注入集合型对象时,singleton Bean和prototype Bean均只存在一份
//prototype Bean有别于其他地方的依赖注入prototype Bean
// 结论三:
// 无论是 Singleton 还是 Prototype Bean 均会执行初始化方法回调
// 不过仅 Singleton Bean 会执行销毁方法回调
scopeBeanByLookip(applicationContext);
scopeBeanByInjection(applicationContext);
//关闭应用上下文
applicationContext.close();
}
private static void scopeBeanByLookip(AnnotationConfigApplicationContext applicationContext) {
for (int i = 0; i < 3; i++) {
// singleton 是共享型 bean 对象
User singleton = applicationContext.getBean("singletonUser", User.class);
System.out.println("singletonUser = " + singleton);
// prototype 是独享型 bean 对象
User prototype = applicationContext.getBean("prototypeUser", User.class);
System.out.println("prototypeUser = " + prototype);
}
}
private static void scopeBeanByInjection(AnnotationConfigApplicationContext applicationContext) {
BeanScopeDemo beanScopeDemo = applicationContext.getBean(BeanScopeDemo.class);
System.out.println("beanScopeDemo.singletonUser = " + beanScopeDemo.singletonUser);
System.out.println("beanScopeDemo.singletonUser1 = " + beanScopeDemo.singletonUser1);
System.out.println("beanScopeDemo.prototypeUser = " + beanScopeDemo.prototypeUser);
System.out.println("beanScopeDemo.prototypeUser1 = " + beanScopeDemo.prototypeUser1);
System.out.println("beanScopeDemo.prototypeUser2 = " + beanScopeDemo.prototypeUser2);
System.out.println("beanScopeDemo.users = " + beanScopeDemo.users);
}
@Override
public void destroy() throws Exception {
System.out.println("当前 BeanScopeDemo Bean 正在销毁中...");
this.prototypeUser.destroy();
this.prototypeUser1.destroy();
this.prototypeUser1.destroy();
this.prototypeUser2.destroy();
// 获取 BeanDefinition
for (Map.Entry<String, User> entry : this.users.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (beanDefinition.isPrototype()) { // 如果当前 Bean 是 prototype scope
User user = entry.getValue();
user.destroy();
}
}
System.out.println("当前 BeanScopeDemo Bean 销毁完成");
}
}
ThreadLocalScope
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package springtest.bean.scope;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
import org.springframework.core.NamedThreadLocal;
import org.springframework.lang.NonNull;
import java.util.HashMap;
import java.util.Map;
/**
* ThreadLocal 级别 Scope
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since
*/
public class ThreadLocalScope implements Scope {
public static final String SCOPE_NAME = "thread-local";
private final NamedThreadLocal<Map<String, Object>> threadLocal = new NamedThreadLocal("thread-local-scope") {
public Map<String, Object> initialValue() {
return new HashMap<>();
}
};
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
// 非空
Map<String, Object> context = getContext();
Object object = context.get(name);
if (object == null) {
object = objectFactory.getObject();
context.put(name, object);
}
return object;
}
@NonNull
private Map<String, Object> getContext() {
return threadLocal.get();
}
@Override
public Object remove(String name) {
Map<String, Object> context = getContext();
return context.remove(name);
}
@Override
public void registerDestructionCallback(String name, Runnable callback) {
// TODO
}
@Override
public Object resolveContextualObject(String key) {
Map<String, Object> context = getContext();
return context.get(key);
}
@Override
public String getConversationId() {
Thread thread = Thread.currentThread();
return String.valueOf(thread.getId());
}
}
ThreadLocalScopeDemo
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package springtest.bean.scope;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import springtest.ioc.overview.domain.User;
/**
* 自定义 Scope {@link ThreadLocalScope} 示例
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since
*/
public class ThreadLocalScopeDemo {
@Bean
@Scope(ThreadLocalScope.SCOPE_NAME)
public User user() {
return createUser();
}
private static User createUser() {
User user = new User();
user.setId(System.nanoTime());
return user;
}
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 注册 Configuration Class(配置类) -> Spring Bean
applicationContext.register(ThreadLocalScopeDemo.class);
applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
// 注册自定义 scope
beanFactory.registerScope(ThreadLocalScope.SCOPE_NAME, new ThreadLocalScope());
});
// 启动 Spring 应用上下文
applicationContext.refresh();
scopedBeansByLookup(applicationContext);
// 关闭 Spring 应用上下文
applicationContext.close();
}
private static void scopedBeansByLookup(AnnotationConfigApplicationContext applicationContext) {
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(() -> {
// user 是共享 Bean 对象
User user = applicationContext.getBean("user", User.class);
System.out.printf("[Thread id :%d] user = %s%n", Thread.currentThread().getId(), user);
});
// 启动线程
thread.start();
// 强制线程执行完成
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static void scopedBeansByInjection(AnnotationConfigApplicationContext applicationContext) {
}
}
总结
获取bean对象的方法有三种:
1、在配置文件中定义bean对象,在代码中通过名称、类型和注解查询等方式获取bean对象;
2、在代码中通过BeanDefinition来定义bean对象,并通过查询类型的方式获取bean对象;
3、在代码中创建配置类(相当于定义Bean),在代码中通过名称、类型和注解查询等方式获取bean对象;