文章目录
spring基础-装配Bean
1、Spring容器和应用上下文
容器是Spring框架实现功能的核心
spring容器并不是只有一个。Spring自带了多个容器实现,可以归为两种不同的类型。
- Bean工厂(由org.springframework.beans.factory.BeanFactory接口定义)是最简单的容器,提供基本的DI支持。
- 应用上下文(由org.springframework.context.ApplicationContext接口定义)基于BeanFactory构建,并提供应用框架级别的服务,例如从属性文件解析文本信息以及发布应用事件给感兴趣的事件监听者。
对于上下文抽象接口,Spring也为我们提供了多种类型的容器实现:
- AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文
- AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载Spring Web应用上下文
- ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源
- XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下文定义
- FileSystemXmlApplicationContext:从文件系统下的一个或多个XML配置文件中加载上下文定义
实例:
ApplicationContext context = new ClassPathXmlApplicationContext("beans1.xml");
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig1.class);
2、装配bean
装配bean有三种方式
- 在XML中进行显式配置
- 在java中显式配置:使用@Configuration+@Bean配置Bean
- 隐式的bean发现机制和自动装配
2.1、在XML中进行显式配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.chenyl.module.model.Person">
<property name="name" value="chenyl"/>
<property name="age" value="18"/>
</bean>
<bean id="person2" class="com.chenyl.module.model.Person">
<property name="name" value="chenyl"/>
<property name="age" value="18"/>
</bean>
</beans>
获取Person实例:
//使用xml方式
{
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = (Person) context.getBean("person");
// Person person = (Person) context.getBean(Person.class);
System.out.println("使用xml方式,获取person实例");
System.out.println(person.toString());
}
2.2、在java中显式配置:使用@Configuration+@Bean配置Bean
@Configuration
public class BeanConfig1 {
@Bean("person1")
public Person person(){
return new Person("chenyl",20);
}
}
获取Person实例:
//使用注解方式
{
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig1.class);
// Person person = context.getBean(Person.class);
Person person = (Person) context.getBean("person1");
System.out.println("使用注解方式,获取person实例");
System.out.println(person.toString());
}
2.3、隐式的Bean发现机制和自动装配
Spring从两个角度来实现自动化装配:
- 组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean
- 自动装配(autowiring):Spring自动满足bean之间的依赖
2.3.1、@ComponentScan注解启动了组件扫描
/**
* 测试带有@Component注解的自动装配
*/
@Configuration
@ComponentScan(value = "com.chenyl.module.model")
public class BeanConfig5 {
}
/**
* 测试自动配置bean,@Component
*/
@Component
public class PersonScan {
private String name;
private Integer age;
public PersonScan(String name, Integer age) {
this.name = name;
this.age = age;
}
}
获取实例:
@Test
public void test01(){
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig5.class);
System.out.println("IOC容器创建完成............");
System.out.println("获取spring容器中所有实例:");
String[] names = context.getBeanDefinitionNames();
for (String name:names) {
System.out.println(name);
}
Object person = context.getBean("personScan");
System.out.println(person.toString());
}
输出结果:
IOC容器创建完成............
获取spring容器中所有实例:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
beanConfig5
personScan
PersonScan{name='null', age=null}
总结:如果没有其他配置的话,@ComponentScan默认扫描与配置类相同的包。如果配置value = “com.chenyl.module.model”,Spring将会扫描这个包以及这个包下的所有子包,查找带有@Component注解的类。
2.3.2、通过XML启动组件扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.chenyl.module.model"/>
</beans>
//使用xml方式
{
ApplicationContext context = neClassPathXmlApplicationContext("beans2.xml")
System.out.println("获取spring容器中所有实例:");
String[] names = context.getBeanDefinitionNames();
for (String name:names) {
System.out.println(name);
}
输出结果:
获取spring容器中所有实例:
personScan
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
3、常用注解
@ComponentScan
进行包扫描会根据注解进行注册组件,value=“包名”
@ComponentScan(value = "com.chenyl.module")
测试实例:
@Test
public void test01(){
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig2.class);
System.out.println("获取spring容器中所有实例:");
String[] names = context.getBeanDefinitionNames();
for (String name:names) {
System.out.println(name);
}
}
运行结果:
获取spring容器中所有实例:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
beanConfig2
beanConfig1
orderController
orderService
person1
FilterType
- ANNOTATION 通过注解类型 列如 @Controller为Controller.class @Service 为 Service.class
- ASSIGNABLE_TYPE 一组具体类 例如PersonController.class
- ASPECTJ 一组表达式,使用Aspectj表达式命中类
- REGEX 一组表达式,使用正则命中类
- CUSTOM 自定义的TypeFilter
excludeFilters
excludeFIlters = Filter[] 根据规则排除组件
@ComponentScan(value = "com.chenyl.module",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
})
使用上面的测试例子测试excludeFilters,运行结果:
获取spring容器中所有实例:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
beanConfig2
beanConfig1
orderService
person1
没有显示orderController
includeFilters
includeFIlters = Filter[]根据规则只包含哪些组件(ps:useDefaultFilters设置为false)
@ComponentScan(value = "com.chenyl.module",includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
使用上面的测试例子测试includeFilters,运行结果:
获取spring容器中所有实例:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
beanConfig2
orderController
只显示包括的Controller和配置中的beanConfig2。其中beanConfig2是由于获取配置类所以必须加载的
@Configuration
@ComponentScan(value = "com.chenyl.module",includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
public class BeanConfig2 {
}
使用自定义TypeFilter
当过滤有特殊要求时,可以实现TypeFilter来进行自定的过滤规则
type = FilterType.CUSTOM
@Configuration
@ComponentScan(value = "com.chenyl.module",includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = {ChenylTypeFilter.class})
},useDefaultFilters = false)
public class BeanConfig2 {
}
public class ChenylTypeFilter implements TypeFilter {
private ClassMetadata classMetadata;
/**
*
* metadataReader:读取到当前正在扫描类的信息
* metadataReaderFactory:可以获取其他任何类的信息
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类注解的信息
AnnotatedTypeMetadata annotatedTypeMetadata = metadataReader.getAnnotationMetadata();
//获取目前正在扫描的类信息
classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
String className = classMetadata.getClassName();
System.out.println("-------->"+className);
if(className.contains("Order")){//带有order的加载
return true;
}
return false;
}
}
运行结果:
-------->com.chenyl.module.config.BeanConfig1
-------->com.chenyl.module.config.ChenylTypeFilter
-------->com.chenyl.module.controller.OrderController
-------->com.chenyl.module.model.Person
-------->com.chenyl.module.service.OrderService
-------->com.chenyl.module.test.BeanConfig2Test
-------->com.chenyl.module.test.BeanTest
-------->com.chenyl.module.test.HashMapTest
获取spring容器中所有实例:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
beanConfig2
orderController
orderService
@Component、@Controller、@Service、@Repository
使用@ComponentScan扫描的时候,能够扫描到@Component、@Controller、@Service、@Repository
@Scope
/**
* prototype:多实例 IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象,而是每次获取的时候才会调用方法创建对象
* singleton:单实例(默认):IOC容器启动的时候会调用方法创建对象并放到IOC容器中
* request:主要针对web应用,递交一次请求创建一个实例
* session:同一个session创建一个实例
*/
@Scope("prototype")
@Bean("person")
public Person person(){
return new Person("chenyl",20);
}
测试多实例:
public class BeanConfig2Test {
@Test
public void test01(){
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig3.class);
System.out.println("获取spring容器中所有实例:");
String[] names = context.getBeanDefinitionNames();
for (String name:names) {
System.out.println(name);
}
Object person1 = context.getBean("person");
Object person2 = context.getBean("person");
System.out.println(person1 == person2);
}
}
运行结果:
获取spring容器中所有实例:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
beanConfig3
person
false
说明person1和person2不是同一个实例
@Lazy
懒加载
容器启动时候不创建对象,仅当第一次使用bean时候创建对象
@Configuration
public class BeanConfig4 {
//给容器注册一个bean,类型为返回值的类型,默认为单实例
/**
* 懒加载:主要针对单实例bean:默认在容器启动的时候创建对象
* 懒加载:容器启动时候不创建对象,仅当第一次使用bean时候创建对象
*/
@Lazy
@Bean("person")
public Person person(){
System.out.println("给容器中添加person..........-");
return new Person("chenyl",20);
}
}
测试懒加载:
public class BeanConfig4Test {
@Test
public void test01(){
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig4.class);
System.out.println("IOC容器创建完成............");
Object person = context.getBean("person");
System.out.println(person.toString());
}
}
运行结果:
给容器中添加person..........-
IOC容器创建完成............
Person{name='chenyl', age=20}
@Conditonal
根据条件注册bean,@Conditional({条件A,条件B…}),同时满足条件A,条件B才能注册bean。
测试实例:根据操作系统的注册person,如果是windows系统就注入chenyl,如果是Linux系统就注入guolin。
新建WinCondition实现Condition接口:
/**
* 条件注册bean
*/
public class WinCondition implements Condition {
/**
* ConditionContext:判断条件能使用的上下文环境
* AnnotatedTypeMetadata:注释信息
*
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//是否是Linux系统
//1.能获取到IOC使用的beanFactory
ConfigurableBeanFactory beanFactory = context.getBeanFactory();
//2. 获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3. 获取当前环境信息
Environment environment = context.getEnvironment();
//4. 获取Bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
if(property.contains("Windows")){
return true;
}
return false;
}
}
/**
* 简单@Conditional 条件注册bean
*/
@Configuration
public class BeanConfig7 {
@Bean("person")
public Person person(){
return new Person("person",20);
}
@Conditional({WinCondition.class})
@Bean("chenyl")
public Person chenyl(){
return new Person("chenyl",20);
}
@Conditional({LinuxCondition.class})
@Bean("guolin")
public Person guolin(){
return new Person("guolin",50);
}
@Conditional({LinuxCondition.class,WinCondition.class})
@Bean("duxl")
public Person duxl(){
return new Person("duxl",50);
}
}
测试:
@Test
public void test01(){
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig7.class);
System.out.println("IOC容器创建完成............");
System.out.println("获取spring容器中所有实例:");
String[] names = context.getBeanDefinitionNames();
for (String name:names) {
System.out.println(name);
}
Map<String, Person> beans = context.getBeansOfType(Person.class);
System.out.println(beans.toString());
}
运行结果:
IOC容器创建完成............
获取spring容器中所有实例:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
beanConfig7
person
chenyl
{person=Person{name='person', age=20}, chenyl=Person{name='chenyl', age=20}}
@Import
同样按流程先新建BeanConfig8配置类
新建Dog.java类----->public class Dog {}
新建Cat.java类---->public class Cat{}
使用import将dog, cat的bean注册到容器中,并测试打印,看容器中是否已加载此类
/**
* 测试@Import功能
*/
@Configuration
@Import({Dog.class, Cat.class})
public class BeanConfig8 {
@Bean("person")
public Person person(){
return new Person("person",20);
}
}
测试:
public class BeanConfig8Test {
@Test
public void test01(){
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig8.class);
System.out.println("IOC容器创建完成............");
System.out.println("获取spring容器中所有实例:");
String[] names = context.getBeanDefinitionNames();
for (String name:names) {
System.out.println(name);
}
}
}
运行结果:
IOC容器创建完成............
获取spring容器中所有实例:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
beanConfig8
com.chenyl.module.spring.model.Dog
com.chenyl.module.spring.model.Cat
person