Spring IOC注解版看这一篇就够用了

Spring-IOC注解版

一、组件注册

1.@Bean

配置类:

package com.cetc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import com.cetc.bean.Person;
//该配置类就等同于配置文件
//Configuration注解标注该类为spring的配置类,该注解的实现上标注了@Compoent,用来说明被该注解标注的类是spring容器的一个组件
@Configuration 
public class MainConfig {
	@Bean(value = "person01")//容器中存放该对象的id值默认为方法名称,如果加上别名,则为别名的值
	public Person person() {
		return new Person("张三",55);
	}
}

测试类:

package com.cetc;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.cetc.bean.Person;
import com.cetc.config.MainConfig;
/**
 * 主测试类
 * @author LZX-PC
 *
 */
public class MainTest {
	@SuppressWarnings("resource")
	public static void main(String[] args) {
		//2.用使用注解从容器中获取对象,id默认为@Bean所注解的方法名
		ApplicationContext applicationContext = 
                                new AnnotationConfigApplicationContext(MainConfig.class);
		Person person = (Person)applicationContext.getBean("person01");
		System.out.println(person);
        //根据类型获取目前spring容器中包含的对象的组件名称
        String[] strings = applicationContext.getBeanNamesForType(Person.class);
		for (String name : strings) {
			System.out.println(name);
		}
	}
}

输出结果:

Person [name=张三, age=55]
person01
2.@ComponentScan

配置类:

package com.cetc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import com.cetc.bean.Person;
/**
1.includeFilters= {@Filter(type = FilterType.ANNOTATION,value= {Controller.class})}
它的意思是只显示被@Controller标注的类,必须搭配useDefaultFilters = false才能生效.
2.excludeFilters= {@Filter(type = FilterType.ANNOTATION,value= {Controller.class})}
它的意思是只显示排除@Controller标注的类,不需要搭配useDefaultFilters = false.
3.FilterType.ANNOTATION:使用注解进行过滤
  FilterType.ASSIGNABLE_TYPE:使用类名进行过滤
  FilterType.CUSTOM:使用自定义的类进行过滤,MyFilter类为自定义类
*/
@Configuration 
@ComponentScans(value = {
	@ComponentScan(value = "com.cetc",
       includeFilters= {
			@Filter(type = FilterType.ANNOTATION,value= {Controller.class}),
			@Filter(type = FilterType.ASSIGNABLE_TYPE,value = {BookService.class}),
			@Filter(type = FilterType.CUSTOM,value = {MyFilter.class})
	},useDefaultFilters = false)
})
public class MainConfig {
	
	@Bean("person01")//容器中存放该对象的id值默认为方法名称,如果加上别名,则为别名的值
	public Person person() {
		return new Person("张三",55);
	}
}

MyFilter

package com.cetc.filter;
import java.io.IOException;
import org.springframework.core.io.Resource;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
/**
	自定义过滤类
*/
public class MyFilter implements TypeFilter{
	//metadataReader:当前类的信息
	//metadataReaderFactory:可以获取到其他类的信息
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		//扫描规定包下面的所有的类
		Resource resource = metadataReader.getResource();
		//获取当前包下面的所有类的类名
		String filename = resource.getFilename();
        //获取类名中包含Dao的类进行输出
		if(filename.contains("Dao")) {
			return true;
		}
		return false;
	}
}

测试类:

package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.config.MainConfig;

public class IOCTest {
	@Test
	public void test01() {
		@SuppressWarnings("resource")
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
		String[] names = applicationContext.getBeanDefinitionNames();
		for (String name : names) {
			System.out.println(name);
		}
	}
}

输出结果:

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
mainConfig
bookController
bookDao
bookService
person01
3.@Scope

配置类:

package com.cetc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import com.cetc.bean.Person;
@Configuration
public class MainConfig2 {
	/**
	 * 1.SCOPE_SINGLETON singleton:单实例的,即IOC容器启动时,该实例就已经生成了,只生成一次,每次调用都是第一        次生成的实例
	 * 2.SCOPE_PROTOTYPE prototype:多实例的,即IOC容器启动时,并未生成该实例,等待调用的时候才生成该实例,并且        每调用一次都生成一个新的实例
	 * 3.TODO SCOPE_REQUEST request
	 * 4.TODO SCOPE_SESSION session
	 */
	@Scope("singleton")
	@Bean
	public Person person() {
		System.out.println("创建Person对象...");
		return new Person("张三",50);
	}
}

测试类:

package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.bean.Person;
import com.cetc.config.MainConfig2;
public class IOCTest {
	@Test
	public void test01() {
		@SuppressWarnings("resource")
		//1.启动IOC容器
		AnnotationConfigApplicationContext applicationContext = new        AnnotationConfigApplicationContext(MainConfig2.class);
		System.out.println("IOC容器已经启动了...");
		//2.调用IOC容器中的实例
		Person person = (Person)applicationContext.getBean("person");
		Person person1 = (Person)applicationContext.getBean("person");
		System.out.println(person == person1);
	}
}

输出结果:

当scope类型为singleton时结果为:
	 创建Person对象...
     IOC容器已经启动了...
     true 
 当scope类型为prototype时结果为:
 	IOC容器已经启动了...
	创建Person对象...
	创建Person对象...
	false
4.@Lazy

配置类:

package com.cetc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import com.cetc.bean.Person;
@Configuration
public class MainConfig2 {
	/**
	 * 单例模式下,IOC容器启动时不会创建Bean,第一次调用时再创建bean,只创建一次
	 */
	@Scope(scopeName = "singleton")
	@Lazy
	@Bean
	public Person person() {
		System.out.println("创建Person对象...");
		return new Person("张三",50);
	}
}

测试类:

package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.cetc.bean.Person;
import com.cetc.config.MainConfig2;
public class IOCTest {
	@Test
	public void test01() {
		@SuppressWarnings("resource")
		AnnotationConfigApplicationContext applicationContext = 
		new AnnotationConfigApplicationContext(MainConfig2.class);
		System.out.println("IOC容器启动成功...");
//		Person person = (Person)applicationContext.getBean("person");
//		Person person1 = (Person)applicationContext.getBean("person");
//		System.out.println(person == person1);
	}
}

输出结果:

13、14、15行代码为未打开时的结果:
	IOC容器启动成功...
13、14、15行代码打开后的结果:
	IOC容器启动成功...
	创建Person对象...
	true
5.@Conditional

1.标注在方法上,意思是该方法满足条件后该@Bean标注的方法才生效

2.标注在类上,意思是该类满足条件后,该配置类总所有的@Bean才生效

源码解读:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
	/**
	*表示该注解允许多个类进行条件过滤,该类必须实现Condition,根据一定的条件筛选后,直至条件返回true
	*然后将该条件类作为过滤的条件
	*/
    
	Class<? extends Condition>[] value();
}

//Condition接口
public interface Condition {
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

条件类1:

package com.cetc.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class WindowsCondition implements Condition{
	/**
	 * 
	 */
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		//获取bean工厂
		ConfigurableListableBeanFactory factory = context.getBeanFactory();
		//获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		//获取环境变量
		Environment environment = context.getEnvironment();
		//所有的类都是在此类中进行注册的
		BeanDefinitionRegistry registry = context.getRegistry();
		String name = environment.getProperty("os.name");
		if(name.contains("Windows")) {
			return true;
		}
		return false;
	}

}

条件类2:

package com.cetc.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class LinuxCondition implements Condition{

	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		//获取bean工厂
		ConfigurableListableBeanFactory factory = context.getBeanFactory();
		//获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		//获取环境变量
		Environment environment = context.getEnvironment();
		//所有的类都是在此类中进行注册的
		BeanDefinitionRegistry registry = context.getRegistry();
		String name = environment.getProperty("os.name");
		if(name.contains("Linux")) {
			return true;
		}
		return false;
	}
}

配置类:

package com.cetc.config;

import java.awt.Window;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import com.cetc.bean.Person;
import com.cetc.condition.LinuxCondition;
import com.cetc.condition.WindowsCondition;
//@Conditional({WindowsCondition.class})
@Configuration
public class MainConfig2 {
	@Conditional({WindowsCondition.class})
	@Bean
	public Person person01() {
		return new Person("window之父",67);
	}
	@Conditional({LinuxCondition.class})
	@Bean
	public Person person02() {
		return new Person("linux之父",48);
	}
}

测试类:

package com.cetc.test;
import java.util.Map;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import com.cetc.bean.Person;
import com.cetc.config.MainConfig2;
public class IOCTest {
	
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
	@Test
	public void test02(){
		ConfigurableEnvironment environment = applicationContext.getEnvironment();
		System.out.println("------->"+environment.getProperty("os.name"));
		Map<String,Person> map = applicationContext.getBeansOfType(Person.class);
		System.out.println(map);
	}
}

输出结果:

//当操作系统为Windows时,输出结果为:
------->Windows 10
{person01=Person [name=window之父, age=67]}

//当操作系统为Linux时,输出结果为:
------->Linux
{person02=Person [name=linux之父, age=48]}
6.@Import

给容器导入组件的方式:

  1. 包扫描+组件标注注解(@Controller、@Service、@Repository、@Component)[自己写的类]或者给该类加上@Congfiguration注解,该注解的其实就是在@Component注解上又封装了一层,可以不配合包扫描单独使用
  2. @Bean[导入第三方包里的组件]
  3. @Import[快速给容器导入一个组件,相较于@Bean注解更简单便捷],有三种方式:
    • 方式一:@Import(要导入容器中的组件),容器会自动注册这个组件,id默认为全类名
    • 方式二:@ImportSelector
  4. 使用Spring提供的FactoryBean进行组件的注入
    • 默认获取到的是工厂bean调用getObject()所创建的对象
    • 要获取到工厂Bean本身,我们需要在id前面加上一个&符号:&beanFactoryBean

源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
	/**
	 * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
	 * or regular component classes to import.
	 */
	Class<?>[] value();
}

方式一:

配置类:

package com.cetc.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.cetc.bean.Color;
@Configuration
@Import(value = {Color.class})
public class MainConfig {
	
}

测试类:

package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.cetc.config.MainConfig;
public class ImportTest {
	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
	
	@Test
	public void test01() {
		printBeanName();
	}
	public void printBeanName() {
		String[] names = context.getBeanDefinitionNames();
		for (String name : names) {
			System.out.println(name);
		}
	}
}

输出结果:

mainConfig
com.cetc.bean.Color

方式二:

配置类:

package com.cetc.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.cetc.bean.Color;
import com.cetc.condition.MyImportSelector;
@Configuration
@Import(value = {Color.class,MyImportSelector.class})
public class MainConfig {
	
}

MyImportSelector类:

package com.cetc.condition;

import java.util.Set;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
 * 自定义要导入的组件
 */
public class MyImportSelector implements ImportSelector {
	/**
	 * 返回值String[]:返回所有注册的全类名
	 * AnnotationMetadata:定义了所有的注解
	 */
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		//获取容器现存在所有注解的类型
		Set<String> types = importingClassMetadata.getAnnotationTypes();
		for (String type : types) {
			System.out.println("--------->"+type);
			//输出结果: --------->org.springframework.context.annotation.Configuration
			//		    --------->org.springframework.context.annotation.Import
		}
		
		return new String[] {"com.cetc.bean.Black","com.cetc.bean.Yellow","com.cetc.bean.Person"};
	}

}

测试类:

package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.cetc.config.MainConfig;
public class ImportTest {
	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
	
	@Test
	public void test01() {
		printBeanName();
	}
	
	public void printBeanName() {
		String[] names = context.getBeanDefinitionNames();
		for (String name : names) {
			System.out.println(name);
		}
	}
}

输出结果:

--------->org.springframework.context.annotation.Configuration
--------->org.springframework.context.annotation.Import
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
mainConfig
com.cetc.bean.Color
com.cetc.bean.Black
com.cetc.bean.Yellow
com.cetc.bean.Person

方式三:

配置类:

package com.cetc.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.cetc.bean.Color;
import com.cetc.condition.MyImportBeanDefinitionRegistrar;
import com.cetc.condition.MyImportSelector;
@Configuration
@Import(value = {Color.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class MainConfig {
	
}

MyImportBeanDefinitionRegistrar类:

package com.cetc.condition;

import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

import com.cetc.bean.RainBow;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
	/**
	 * @param annotationMetadata:容器中注解的相关信息
	 * @param registry:注册类
	 */
	public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
		
		boolean flag1 = registry.containsBeanDefinition("com.cetc.bean.Black");
		boolean flag2 = registry.containsBeanDefinition("com.cetc.bean.Yellow");
		if(flag1 && flag2) {
			//指定bean名
			RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
			registry.registerBeanDefinition("rainBow", beanDefinition);
		}
	}


}

测试类:

package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.cetc.config.MainConfig;
public class ImportTest {
	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
	
	@Test
	public void test01() {
		printBeanName();
	}
	
	public void printBeanName() {
		String[] names = context.getBeanDefinitionNames();
		for (String name : names) {
			System.out.println(name);
		}
	}
}

输出结果:

mainConfig
com.cetc.bean.Color
com.cetc.bean.Black
com.cetc.bean.Yellow
com.cetc.bean.Person
rainBow

第四种方式:

配置类:

package com.cetc.bean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ColorFactoryBean implements FactoryBean<Color>{
	private static int i = 1;
	/**
	 * 通过getObject获取往工厂里面注入的bean
	 */
	public Color getObject() throws Exception {
		System.out.println("调用第"+i+"次");
		i++;
		return new Color();
	}
	/**
	 * true :为单实例的,只创建一次Color对象
	 * false : 为多实例的,创建多个Color对象
	 */
	public boolean isSingleton() {
		return true;
	}
	public Class<?> getObjectType() {
		return null;
	}
}

测试类:

package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.cetc.bean.ColorFactoryBean;
public class ImportTest {
	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ColorFactoryBean.class);
	@Test
	public void test01() {
		printBeanName();
	}
	
	public void printBeanName() {
		Object bean1 = context.getBean("colorFactoryBean");
		Object bean2 = context.getBean("colorFactoryBean");
		System.out.println("容器中该类的类型为:"+bean1.getClass());
		System.out.println(bean1 == bean2);
	}
}

输出结果:

调用第1次
容器中该类的类型为:class com.cetc.bean.Color
true

如果要获取工厂Bean本身:

测试类:

package com.cetc.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.cetc.bean.ColorFactoryBean;
public class ImportTest {
	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ColorFactoryBean.class);
	@Test
	public void test01() {
		printBeanName();
	}
	
	public void printBeanName() {
		Object bean1 = context.getBean("&colorFactoryBean");
		Object bean2 = context.getBean("&colorFactoryBean");
		System.out.println("容器中该类的类型为:"+bean1.getClass());
		System.out.println(bean1 == bean2);
	}
}

输出结果:

容器中该类的类型为:class com.cetc.bean.ColorFactoryBean$$EnhancerBySpringCGLIB$$f7f88f6e
true

二、生命周期


关于容器管理Bean的生命周期:

​ 我们可以自己定义bean的生命周期,当bean执行到当前生命周期时调用我们自定义的方法

​ 创建Bean ------------------>初始化Bean------------------->销毁Bean

  1. 构造对象:

    • 单实例:容器启动的时候创建对象
    • 多实例:在每次调用的时候创建对象
  2. 初始化:

    对象创建完成,并赋值好,调用初始化方法

  3. 销毁:

    • 单实例情况下,当容器关闭后,调用我们自定义的销毁的方法
    • 多实例情况下,需要我们手动关闭容器,它不会调用我们自定义的销毁方法

    实现方式:
    (1)采用@Bean指定init-method和destory-method
    (2)通过让Bean实现InitializationBean(定义初始化逻辑)和DisposableBean(定义销毁逻辑)管理生命周期
    (3)使用JSR250:

    ​ @PostConstruct:在bean创建完成并且赋值完成后,来执行初始化方法

    ​ @PreDestroy: 在容器销毁Bean之前通知我们进行清理操作

    (4)使用BeanPostProcessor(后置处理器)

    ​ postProcessBeforeInitialization:在创建好对象并赋值结束之后立即调用

    ​ postProcessAfterInitialization:在初始化完成之后立即调用

    4.BeanPostProcessor原理

    //创建对象,交给IOC容器管理,然后给属性赋值

    1.populateBean(beanName, mbd, instanceWrapper);

    2.初始化

    {

    //前置处理器

    2.1.applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

    //调用InitializationBean或者的@Bean指定的方法或者JSR250注解标注的方法

    2.2.invokeInitMethods(beanName, wrappedBean, mbd);

    //后置处理器

    2.3.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

    }

    因此,执行顺序是前置处理器—>JSR250—>InitializationBean—>后置处理器---->JSR250的destroy—>InitializationBean的destroy

    4.Spring底层对BeanPostProcessor的应用:

    ​ bean赋值、注入其它组件等等都用到的前置处理器

1. @Bean指定初始化和销毁方法
注解版:

单实例

配置类:

package com.cetc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import com.cetc.bean.Car;
public class MainConfigOfLifeStyle {
	@Bean(initMethod = "init" , destroyMethod = "destory")
	@Scope(value = "singleton")
	public Car car() {
		return new Car();
	}
}

Car:

package com.cetc.bean;

public class Car {
	public Car() {
		System.out.println("创建Car..........................");
	}
	
	public void init() {
		System.out.println("初始化Car.........................");
	}
	
	public void destory() {
		
		System.out.println("销毁Car............................");
	}
}

测试类:

package com.cetc.test;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.cetc.bean.Car;
import com.cetc.config.MainConfigOfLifeStyle;

public class LifeStyleTest {
	@Test
	public void test01() {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeStyle.class);
		Car car = (Car) context.getBean("car");
		System.out.println(car);
		context.close();
	}
}

输出结果:

初始化Car.........................
com.cetc.bean.Car@a38d7a3
销毁Car............................

当@Scope的value值为prototype时,输出结果为:

创建Car..........................
初始化Car.........................
com.cetc.bean.Car@a38d7a3
2. InitializationBean和DisposableBean管理生命周期

注解版:

配置类:

package com.cetc.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Cat implements InitializingBean,DisposableBean{
	
	public Cat() {
		System.out.println("cat.........constructor.........");
	}
	public void destroy() throws Exception {
		System.out.println("cat.....destroy.......");
	}

	public void afterPropertiesSet() throws Exception {
		System.out.println("cat.......afterPropertiesSet........");
	}

}

测试类:

	@Test
	public void test02() {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Cat.class);
		Cat cat = (Cat) context.getBean("cat");
		System.out.println(cat);
		context.close();
	}

输出结果:

cat.........constructor.........
cat.......afterPropertiesSet........
com.cetc.bean.Cat$$EnhancerBySpringCGLIB$$4fb08bec@1dd02175
cat.....destroy.......
3. 使用JSR250

配置类:

@Configuration
public class Dog implements InitializingBean,DisposableBean{

	public Dog() {
		System.out.println("dog..........construct.........");
	}
	//创建对象并且赋值完成之后调用
	@PostConstruct
	public void init() {
		System.out.println("Dog............PostConstruct........");
	}
	
	public void afterPropertiesSet() throws Exception {
		System.out.println("dog........afterPropertiesSet............");
	}
	
	//容器移除对象之前
	@PreDestroy
	public void preDestroy() {
		System.out.println("dog.........preDestory.......");
	}
	
	public void destroy() throws Exception {
		System.out.println("dog.........destroy........");
	}
}

测试类:

	@Test
	public void test03() {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Dog.class);
		Dog dog = (Dog) context.getBean("d1og");
		context.close();
	}

输出结果:

dog..........construct.........
Dog............PostConstruct........
dog........afterPropertiesSet............
dog.........preDestory.......
dog.........destroy........
4. 实现BeanPostProcessor接口

配置类:

@Configuration
@ComponentScan("com.cetc.bean")
public class MainConfigOfLifeStyle {

	@Bean
	public Dog dog() {
		return new Dog("柴犬...");
	}
}

Dog类:

package com.cetc.bean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class Dog implements InitializingBean,DisposableBean{
	private String name;
	
	public Dog(String name) {
		super();
		System.out.println("dog..........construct........."+name);
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Dog() {
		System.out.println("dog..........construct.........");
	}
	//创建对象并且赋值完成之后调用
	@PostConstruct
	public void init() {
		System.out.println("Dog............PostConstruct........");
	}
	
	public void afterPropertiesSet() throws Exception {
		System.out.println("dog........afterPropertiesSet............"+this.name);
	}
	
	//容器移除对象之前
	@PreDestroy
	public void preDestroy() {
		System.out.println("dog.........preDestory......."+this.name);
	}
	
	public void destroy() throws Exception {
		System.out.println("dog.........destroy........"+this.name);
	}
}

MyBeanPostProcessor类:

package com.cetc.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
 * 后置处理器
 * @author LZX-PC
 *
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("....postProcessAfterInitialization...."+ beanName);
		return bean;
		
	}
	
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("....postProcessBeforeInitialization...."+beanName);
		return bean;
	}
}

测试类:

	@Test
	public void test04() {
		AnnotationConfigApplicationContext context = new 		            AnnotationConfigApplicationContext(MainConfigOfLifeStyle.class);
		context.close();
	}

输出结果:

dog..........construct.........柴犬...
....postProcessBeforeInitialization....dog
Dog............PostConstruct........
dog........afterPropertiesSet............柴犬...
....postProcessAfterInitialization....dog
dog.........preDestory.......柴犬...
dog.........destroy........柴犬...
5. Spring底层对BeanPostProcessor的应用

​ 例如:ApplicationContextAware,首先ApplicationContextAware是一个接口,ApplicationContextAwareProcessor实现了BeanPostProcessor,下面请看源码分析:

ApplicationContextAware类:

public interface ApplicationContextAware extends Aware {
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

ApplicationContextAwareProcessor部分源码:

class ApplicationContextAwareProcessor implements BeanPostProcessor {

	private final ConfigurableApplicationContext applicationContext;

	private final StringValueResolver embeddedValueResolver;

	@Override
	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
		AccessControlContext acc = null;

		if (System.getSecurityManager() != null &&
				(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
						bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
						bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					invokeAwareInterfaces(bean);
					return null;
				}
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}

//
private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof EnvironmentAware) {
				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
			}
			if (bean instanceof EmbeddedValueResolverAware) {
				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
			}
			if (bean instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
			}
			if (bean instanceof ApplicationEventPublisherAware) {
				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
			}
			if (bean instanceof MessageSourceAware) {
				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
			}
            //判断该bean是否是ApplicationContextAware的实现类,如果是,则执行ApplicationContextAware中定义			的方法,并且给applicationContext赋值
			if (bean instanceof ApplicationContextAware) {
				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
			}
		}
	}
}

三、属性赋值

1. @Value&@PropertyValue

使用@Value赋值:

  1. 基本数值
  2. SPEL,#{}
  3. 可以写${},从属性中赋值,需要配合@PropertyValue使用

配置类:

@Configuration
@PropertySources(
		{
			@PropertySource(value = {"classpath:/person.properties"}),
			@PropertySource(value = 	   {"classpath:/person1.properties","classpath:/person2.properties"})
		}
	)
public class MainConfigPropertyValues {
	@Bean
	public Person person() {
		return new Person();
	}
}


properties文件:

person.nickName=xiao zhangsan 

实体类:

public class Person {
	@Value("zhangsan")
	private String name;
	@Value("#{20-2}")
	private Integer age;
	@Value("${person.nickName}")
	...省略toString,get,set方法
}

测试类:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigPropertyValues.class);
	@Test
	public void test01() {
		Person person = (Person) context.getBean("person");
		System.out.println(person);
		context.close();
	}

输出结果:

Person [name=zhangsan, age=18, nickName=xiao zhangsan]

四、自动装配

1. @Autowired&@Qualifier&@Primary

@Autowired&@Qualifier&@Primary配合进行自动注入:

  1. 默认按照类型进行装配,即找到容器中该类型的bean是谁,有几个这样类型的bean

  2. 如果找到有多个相同类型的组件,再根据属性的名称去作为ID去容器中查找,即

    @Autowired private BookService bookService;中的bookService去容器中查找

  3. @Qualifier(“bookDao”):使用@Qualifier指定要装配的组件的id,而不是属性名

  4. 自动装配无论是根据类型来找,还是属性名或者是@Qualifier指定的ID来找,前提是容器中得有组件注入,

    如果没有,则会报错,我们可以通过@Autowired(required = false)来自动注入一个组件,找不到的话则为null

  5. @Primary指定最高优先级,不能喝@Qualifier同时使用,它用于指定优先注入哪个组件

配置类:

@Configuration
@ComponentScan(value = {"com.cetc.service","com.cetc.dao"})
public class MainConfigOfAutowired {
	@Bean("bookDao02")
	public BookDao bookDao() {
		BookDao dao = new BookDao();
		dao.setFlag("1");
		return dao;
	}
}

BookService:

@Service
public class BookService {
	@Qualifier("bookDao")
	@Autowired
	private BookDao bookDao;
	
	public void print() {
		System.out.println(bookDao);
	}
	public BookDao getBookDao() {
		return bookDao;
	}

	public void setBookDao(BookDao bookDao) {
		this.bookDao = bookDao;
	}
}

BookDao:

@Repository("bookDao")
public class BookDao {
	private String flag = "0";

	public String getFlag() {
		return flag;
	}

	public void setFlag(String flag) {
		this.flag = flag;
	}
	@Override
	public String toString() {
		return "BookDao [flag=" + flag + "]";
	}
}

测试类:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
	@Test
	public void test01() {
		BookService bookService = context.getBean(BookService.class);
		bookService.print();
		context.close();
	}

输出结果:

BookDao [flag=0]
2. @Autowired的其它使用

@Autowired除了放到属性位置外,还可以放置到参数、构造器、方法位置上

  1. 放到方法位置: 放到set方法位置,进行对象注入,默认是从容器中拿
  2. 放到构造器位置: 当有且只有一个有参构造器时,直接可以省略
  3. 参数位置: @Bean标注的方法上,参数位置的@Autowired注解也可以省略

标注在参数位置:

@Component
public class Boss {
	private Money money;
	public Money getMoney() {
		return money;
	}
    //标注在参数位置,默认是从容器中拿money对象,当然,Money首先得是容器的一个组件
	@Autowired
	public void setMoney(Money money) {
		this.money = money;
	}
	
	@Override
	public String toString() {
		return "Boss [money=" + money + "]";
	}
}

标注在构造器上:

@Component
public class Boss {
	private Money money;
	
	public Money getMoney() {
		return money;
	}
	/**容器初始化构建对象时,默认调用的是无参构造器,当有且只有一个有参构造器时,容器会调用有参构造,并且该注解可         以省略,也可以加到参数位置,也可以省略,默认是从容器中拿的对象,即下面三种方式等价:
       	 @Autowired
		public Boss(Money money) {
		 super();
          System.out.println("执行了有参构造器....");
		 this.money = money;
		}
		
		public Boss(@Autowird Money money) {
            super();
            System.out.println("执行了有参构造器....");
            this.money = money;
        }
        
     	public Boss(Money money) {
            super();
            System.out.println("执行了有参构造器....");
            this.money = money;
        }
	*/
	@Autowired
	public Boss(@Autowird Money money) {
		super();
        System.out.println("执行了有参构造器....");
		this.money = money;
	}

	public void setMoney(Money money) {
		this.money = money;
	}

	@Override
	public String toString() {
		return "Boss [money=" + money + "]";
	}
}

标注在参数位置:

@Configuration
@ComponentScan(value = {"com.cetc.bean"})
public class MainConfigOfAutowired {
	//这种情况下,money对象从容器中获取,@Autowired也可以省略
	@Bean
	public Car car(@Autowired Money money) {
		Car car = new Car();
		car.setMoney(money);
		return car;
	}
}
3. @Resource&@Inject

@Resource&@Inject:

  1. @Resources(JSR250)注解,@Inject(JSR330)java规范的注解
  2. @Resources按照属性名称进行注入,不能配合@Primary以及没有required = false
  3. @Inject能配合@Primary使用,但是没有required = false以及注解后面不能指定一些属性,如name属性,不太实用

配置类同上

BookService:

	//@Resource(name = "bookDao02")
	@Inject//后面不能指定值
	private BookDao bookDao;
	public void print() {
		System.out.println(bookDao);
	}
	public BookDao getBookDao() {
		return bookDao;
	}

	public void setBookDao(BookDao bookDao) {
		this.bookDao = bookDao;
	}
4. Aware注入Spring底层组件

详解见生命周期-BeanPostProcessor的应用

Aware接口的实现类:

微信图片_20200919111718

配置类:

@Component
public class Color implements ApplicationContextAware,EmbeddedValueResolverAware,BeanNameAware{
	
	public ApplicationContext applicationContext = null;
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		System.out.println("获取IOC容器:"+applicationContext);
		this.applicationContext = applicationContext;
	}
	
	public void setBeanName(String name) {
		System.out.println("current bean name is :"+name);
	}
	
	public void setEmbeddedValueResolver(StringValueResolver resolver) {
		String stringValue = resolver.resolveStringValue("你好啊,${os.name},我是#{12*30}");
		System.out.println(stringValue);
	}
}

配置类:

@Configuration
@ComponentScan(value = {"com.cetc.bean"})
public class MainConfigOfAutowired {
}

测试类:

private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
	
	@Test
	public void test01() {
	}

输出结果:

你好啊,Windows 10,我是360
获取IOC容器:org.springframework.context.annotation.AnnotationConfigApplicationContext@59f95c5d: startup date [Sat Sep 19 11:26:24 CST 2015]; root of context hierarchy
5. @Profile
  1. 注解源码:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
	String[] value();
}
  1. 基本规则:
  • 标注在方法上:先由方法向容器中注入组件,然后约定环境的名字,接下来是启动时具体激活哪个约定好的名字。
  • 标记在类上,表示只有启动时的环境为当前配置类约定的环境时,该配置类下的方法才起作用
  • 最后,在配置类中配置的其他方法不受标注在方法上的@Profile影响,容器启动,然后正常注入组件
  1. 激活方法:
  • 在启动时添加环境变量: -Dspring.profiles.active=环境定义的名称(如 test、dev、prod)
  • 使用代码激活,见代码

jdbc.properties

db.username=root
db.password=root
db.driverClass=com.jdbc.mysql.Driver
db.testUrl=jdbc:mysql://localhost:3306/test
db.devUrl=jdbc:mysql://localhost:3306/dev
db.prodUrl=jdbc:mysql://localhost:3306/produ

配置类:

@Configuration
@PropertySource(value = "classpath:/jdbc.properties")
public class MainConfigProfile {
	@Value("db.username")
	private String userName;
	@Value("db.password")
	private String password;
	@Value("db.driverClass")
	private String driverClass;
	@Value("db.testUrl")
	private String testUrl;
	@Value("db.devUrl")
	private String devUrl;
	@Value("db.prodUrl")
	private String prodUrl;
	
	//添加环境属性
	@Profile("test")
	@Bean("test")
	public DataSource dataSource() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(userName);
		dataSource.setPassword(password);
		dataSource.setJdbcUrl(testUrl);
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
    
	@Profile("dev")
	@Bean("dev")
	public DataSource dataSource01() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(userName);
		dataSource.setPassword(password);
		dataSource.setJdbcUrl(devUrl);
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
    
	//@Profile("default"):当是default,不需要任何激活,容器启动候,默认使用该环境
	@Profile("prod")
	@Bean("prod")
	public DataSource dataSource02() throws Exception {
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(userName);
		dataSource.setPassword(password);
		dataSource.setJdbcUrl(prodUrl);
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
    
    //只要不在该类上添加@Profile,该对象的注入是不受其他方法影响的
	@Bean
	public Car car() {
		return new Car();
	}
}

测试类:

public class MainConfigProfileTest {
	private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigProfile.class);
	
	@Test
	public void test01() {
		String[] arrs = context.getBeanNamesForType(DataSource.class);
		for (String arr : arrs) {
			System.out.println(arr);
		}
		Object bean = context.getBean(Car.class);
		System.out.println(bean);
	}
	
}

输出结果:

dev
Car [money=null]

使用代码激活环境变量:

@Test
	public void test01() {
		//启动IOC容器
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
		//设置环境变量
		context.getEnvironment().setActiveProfiles("dev");
		//注册组件
		context.register(MainConfigProfile.class);
		//刷新容器
		context.refresh();
		
		String[] arrs = context.getBeanNamesForType(DataSource.class);
		for (String arr : arrs) {
			System.out.println(arr);
		}
		Object bean = context.getBean(Car.class);
		System.out.println(bean);
	}

输出结果:

dev
Car [money=null]
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值