相关依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
配置文件方式:
使用xml方式配置bean到IOC容器中
<?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.lb.spring.day1.part1.Person">
<property name="name" value="lb"></property>
<property name="age" value="19"></property>
</bean>
</beans>
public class BeanTest {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
Person person = (Person) app.getBean("person");
System.out.println(person);
}
}
结果:
Person{name='lb', aga=19}
注解方式:
@Configuration
@Configuration 等同于Spring的配置文件.
Spring注入bean的方式
- @Bean -- 导入第三方的类或包的组件,比如有一个第三方的类A,需要导入到IOC容器中使用
- 包扫描+组件的表示注解(@ComponentScan + @Controller, @Service, @Responsitory, @Component), 一般针对自己写的类,使用这个
- @Import:快速给容器导入一个或多个组件
- @Import(要导入的容器的组件):容器会自动注册这个组件,bean的id为全类名
- ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
- ImportBeanDefinitionRegistrar:可以手动添加组件到IOC容器, 所有Bean的注册可以使用BeanDifinitionRegistry
- 使用Spring提供的FactoryBean(工厂bean进行注册)
@Bean
将Bean注入到IOC容器中
@Configuration
public class MyConfigration1 {
@Bean //将bean注入到IOC容器中,默认为单例模式,如果不设置bean的id名称默认方法名为bean的id名称
public Person person01(){
Person person = new Person("lb",20);
return person;
}
@Bean("myPerson") //设置了Bean的id名称
public Person person(){
Person person = new Person("lb",21);
return person;
}
}
public class Part2Test {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration1.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names){
System.out.println(name);
}
Person person = (Person) app.getBean("person01");
System.out.println(person);
Person person2 = (Person) app.getBean("myPerson");
System.out.println(person2);
}
}
结果:
myConfigration1
person01
myPerson
Person{name='lb', aga=20}
Person{name='lb', aga=21}
Condition接口
自定义类实现Condition接口,配合@Conditional 和 @Bean使用,可以有条件的注入
/**
* 如果系统为Windows, 则向IOC容器中注入被注解引用的类
*/
public class WinCondition implements Condition {
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String name = environment.getProperty("os.name");
if (name.contains("Windows")){
return true;
}
return false;
}
}
/**
* 如果系统为Linux, 则向IOC容器中注入被注解引用的类
*/
public class LinuxCondition implements Condition {
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String name = environment.getProperty("os.name");
if (name.contains("Linux")){
return true;
}
return false;
}
}
@Configuration
public class MyConfigration6 {
@Bean
public Person person(){
return new Person("person",25);
}
@Conditional(value = WinCondition.class)
@Bean("lb")
public Person lb(){
return new Person("lb",18);
}
@Conditional(value = LinuxCondition.class)
@Bean("lb2")
public Person lb2(){
return new Person("lb2",19);
}
}
public class Part6Test {
@Test
public void test() {
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration6.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
System.out.println("IOC容器已经加载完成");
}
}
接口: 测试机器系统为window7
myConfigration6
person
lb
IOC容器已经加载完成
@ComponentScan
value属性
Spring扫描包的路径
@Configuration
@ComponentScan(value = "com.lb.spring.day1.part3")
public class MyConfigration2 {
@Bean
public Person person(){
Person person = new Person("lb",20);
return person;
}
}
@Controller
public class MyController {
}
@Repository
public class MyDao {
}
@Service
public class MyService {
}
public class Part3Test {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration2.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names){
System.out.println(name);
}
}
}
结果:
myConfigration2
myController
myDao
myService
person
includeFilters属性
扫描的包中,包含哪些内容,但是必须和useDefaultFilters属性同时使用,默认为true,需要修改成false. includeFilters才能过滤成功:
@Configuration
@ComponentScan(value = "com.lb.spring.day1.part3",includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
public class MyConfigration2 {
@Bean
public Person person(){
Person person = new Person("lb",20);
return person;
}
}
结果:
只注入了Controller注解的类
myConfigration2
myController
person
excludeFilters属性
扫描的包中,不包含哪些内容,useDefaultFilters=true
FilterType.ANNOTATION 为注解,与classes使用
FilterType.ASSIGNABLE_TYPE为具体的类,与value使用
@Configuration
@ComponentScan(value = "com.lb.spring.day1.part3",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {MyController.class})
})
public class MyConfigration2 {
@Bean
public Person person(){
Person person = new Person("lb",20);
return person;
}
}
结果:
myConfigration2
myDao
myService
person
FileType
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;比如按BookService类型
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口
自定义规则: implements TypeFilter
public class LbTypeFilter implements TypeFilter {
/**
* @param metadataReader 读取到正在扫描类的信息
* @param metadataReaderFactory
* @return
* @throws IOException
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
ClassMetadata classMetadata = metadataReader.getClassMetadata();
String className = classMetadata.getClassName();
System.out.println("--------------------"+className);
if (className.contains("controller")){
return true;
}
return false;
}
}
@Configuration
@ComponentScan(value = "com.lb.spring.day1.part3",excludeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM,value = {LbTypeFilter.class})
})
public class MyConfigration2 {
@Bean
public Person person(){
Person person = new Person("lb",20);
return person;
}
}
结果:
myConfigration2
myDao
myService
person
@Import
使用@Import直接导入类
public class Dog {
}
public class Cat {
}
@Configuration
@Import(value = {Dog.class, Cat.class})
public class MyConfigration7 {
@Bean
public Person person(){
return new Person("person",25);
}
}
public class Part7Test {
@Test
public void test() throws Exception {
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration7.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
结果:
可以发下Dog 和 Cat已经注入到Spring容器中,bean的id为类的全类名
myConfigration7
com.lb.spring.day2.part7.bean.Dog
com.lb.spring.day2.part7.bean.Cat
person
ImportSelector 接口
使用ImportSelector接口配合@Import使用,将一组bean注入到IOC容器中, 注意注入类为类的全路径
public class Fish {
}
public class Tiger {
}
public class LbImportSelector implements ImportSelector {
/**
* @param annotationMetadata 当前标注@Import注解类的所有注解信息,不止能获取到import注解,还能获取到其他注解
* @return
*/
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//批量将bean注入到IOC容器中
return new String[]{"com.lb.spring.day2.part7.bean.Fish","com.lb.spring.day2.part7.bean.Tiger"};
}
}
@Configuration
@Import(value = {Dog.class, Cat.class, LbImportSelector.class})
public class MyConfigration7 {
@Bean
public Person person(){
return new Person("person",25);
}
}
结果:
Fish 和 Tiger已经注入到IOC容器中,并且bean 的 id是全类名
myConfigration7
com.lb.spring.day2.part7.bean.Dog
com.lb.spring.day2.part7.bean.Cat
com.lb.spring.day2.part7.bean.Fish
com.lb.spring.day2.part7.bean.Tiger
person
ImportBeanDefinitionRegistrar接口
使用ImportBeanDefinitionRegistrar接口配合@Import,可以将多个Bean加入到IOC容器中,并且可以设置bean的id
public class Pig {
}
public class LbImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* @param annotationMetadata 当前类的注解信息
* @param beanDefinitionRegistry BeanDefinitionz注册类 把所有需要添加到容器中的bean调用registerBeanDefinition自定义手工注册到IOC容器中
*/
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
boolean dogFlag = beanDefinitionRegistry.containsBeanDefinition("com.lb.spring.day2.part7.bean.Dog");
boolean catFlag = beanDefinitionRegistry.containsBeanDefinition("com.lb.spring.day2.part7.bean.Cat");
if (dogFlag && catFlag){//如果IOC容器中已经注入了Dog和Cat
RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class);
beanDefinitionRegistry.registerBeanDefinition("pig",beanDefinition);
}
}
}
@Configuration
@Import(value = {Dog.class, Cat.class, LbImportSelector.class, LbImportBeanDefinitionRegistrar.class})
public class MyConfigration7 {
@Bean
public Person person(){
return new Person("person",25);
}
}
结果:
在自定义的ImportBeanDefinitionRegistrar中判断容器中是否已经存在Dog和Cat,如果存在则将Pig加入到IOC容器中,bean的id为pig
myConfigration7
com.lb.spring.day2.part7.bean.Dog
com.lb.spring.day2.part7.bean.Cat
com.lb.spring.day2.part7.bean.Fish
com.lb.spring.day2.part7.bean.Tiger
person
pig
自定义FactoryBean
通过实现的FactoryBean接口,往IOC容器中注册类
public class Monkey {
private String name;
public Monkey() {
}
public Monkey(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class LbBeanFactory implements FactoryBean<Monkey> {
public Monkey getObject() throws Exception {
return new Monkey("taotao");
}
public Class<?> getObjectType() {
return Monkey.class;
}
public boolean isSingleton() {
return false;
}
}
@Configuration
@Import(value = {Dog.class, Cat.class, LbImportSelector.class, LbImportBeanDefinitionRegistrar.class})
public class MyConfigration7 {
@Bean
public Person person(){
return new Person("person",25);
}
@Bean
public LbBeanFactory lbBeanFactory(){
return new LbBeanFactory();
}
}
public class Part7Test {
@Test
public void test() throws Exception {
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration7.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
//获取BeanFactory 注入的对象
Monkey monkey = (Monkey) app.getBean("lbBeanFactory");
System.out.println(monkey.getClass().getName());
System.out.println(monkey.getName());
System.out.println("---------------------------");
//获取LbBeanFactory本身对象
LbBeanFactory lbBeanFactory = (LbBeanFactory) app.getBean("&lbBeanFactory");
System.out.println(lbBeanFactory.getClass().getName());
System.out.println("IOC容器已经加载完成");
}
}
结果:
可以从容器中得到id为lbBeanFactory的Moneky实例,并且通过id="&lbBeanFactory"可以从容器中得到自定义BeanFactory(LbBeanFactory)的实例
myConfigration7
com.lb.spring.day2.part7.bean.Dog
com.lb.spring.day2.part7.bean.Cat
com.lb.spring.day2.part7.bean.Fish
com.lb.spring.day2.part7.bean.Tiger
person
lbBeanFactory
pig
com.lb.spring.day2.part7.bean.Monkey
taotao
---------------------------
com.lb.spring.day2.part7.LbBeanFactory
IOC容器已经加载完成
@Scope
//给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
/*
* prototype:多实例: IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象, 而是每次获取的时候才会调用方法创建对象
* singleton:单实例(默认):IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿同一个bean
* request: 主要针对web应用, 递交一次请求创建一个实例
* session:同一个session创建一个实例
*/
默认配置:单例
@Configuration
public class MyConfigration3 {
@Scope
@Bean
public Person person(){
Person person = new Person("lb",20);
return person;
}
}
public class Part4Test {
@Test
public void test() {
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration3.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
Person person = (Person) app.getBean("person");
Person person2 = (Person) app.getBean("person");
System.out.println(person == person2);
}
}
结果:
myConfigration3
person
true
多实例:
@Configuration
public class MyConfigration3 {
@Scope("prototype")
@Bean
public Person person(){
Person person = new Person("lb",20);
return person;
}
}
public class Part4Test {
@Test
public void test() {
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration3.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
Person person = (Person) app.getBean("person");
Person person2 = (Person) app.getBean("person");
System.out.println(person == person2);
}
}
结果:
myConfigration3
person
false
@Lazy
延迟加载,一般的Bean在spring容器初始化时会加载到容器中,但是使用@Lazy在容器启动时不会立刻实例化,只有再被调用的时候才会被实例化到容器中
在不使用@Lazy时:
@Configuration
public class MyConfigration4 {
@Bean
public Person person(){
Person person = new Person("lb",25);
System.out.println("Person add to IOC");
return person;
}
}
public class Part5Test {
@Test
public void test() {
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration4.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
System.out.println("IOC容器已经加载完成");
Person person = (Person) app.getBean("person");
System.out.println(person);
}
}
结果:
在容器初始化时已经将Person注入到容器中
Person add to IOC
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
myConfigration4
person
IOC容器已经加载完成
Person{name='lb', aga=25}
使用@Lazy:
@Configuration
public class MyConfigration4 {
@Lazy
@Bean
public Person person(){
Person person = new Person("lb",25);
System.out.println("Person add to IOC");
return person;
}
}
public class Part5Test {
@Test
public void test() {
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration4.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
System.out.println("IOC容器已经加载完成");
Person person = (Person) app.getBean("person");
System.out.println(person);
}
}
结果:
容器先初始化成功,在调用时才将Person添加到IOC 容器中
myConfigration4
person
IOC容器已经加载完成
Person add to IOC
Person{name='lb', aga=25}
@Value
使用@Value给类的属性赋值
- 直接赋值基本字符 : wangcai
- 使用SpringEL表达式:#{10-5} 等等
- 读取配置文件中的值: ${xxx.xxx}, //读取到的值被存储在环境变量中
@Configuration
//使用@PropertySource进行配置文件的读取,可以读取多个文件
@PropertySource(value = {"classpath:/test.properties"})
public class MyConfigration13 {
@Bean
public Dog dog(){
return new Dog();
}
}
public class Dog {
//直接赋值字符串
@Value("wangcai")
private String name;
//使用SpringEL表达式赋值
@Value("#{10-5}")
private Integer age;
//从配置文件中读取
@Value("${dog.color}")
private String color;
public Dog() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
}
public class Part13Test {
@Test
public void test() throws Exception {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(MyConfigration13.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names){
System.out.println(name);
}
Dog dog = (Dog) app.getBean("dog");
System.out.println(dog);
ConfigurableEnvironment environment = app.getEnvironment();
//Spring读取的配置文件信息,存储在环境变量中
System.out.println("environment--->"+environment.getProperty("dog.color"));
System.out.println("IOC 容器初始化完成....");
}
}
结果:
根据@Value给Dog属性分别赋值,使用@PropertySource读取配置文件
myConfigration13
dog
Dog{name='wangcai', age=5, color='yellow'}
environment--->yellow
IOC 容器初始化完成....