1、组件注册
@Configuration&@Bean给容器中注册组件
@ComponentScan-自动扫描组件&指定扫描规则
自定义TypeFilter指定过滤规则
com.pc.Bean.Car
@Component
public class Car {
}
public class GilrFriend {
}
com.pc.Config.MyTypeFilter
@Configuration
//@ComponentScan(value={"com.pc.Bean"})
//扫描包 注册组件
@ComponentScans(value=@ComponentScan(value={"com.pc.Bean","com.pc.Controller"},
includeFilters = {
// @ComponentScan.Filter(type=FilterType.ANNOTATION,value=Controller.class),
@ComponentScan.Filter(type = FilterType.CUSTOM,value = {MyTypeFilter.class})
},
excludeFilters = @ComponentScan.Filter(),useDefaultFilters = false))
//useDefaultFilters = false 扫描时包的时候不使用默认的过滤器 例如FilterType.ANNOTATION
//@ComponentScan value:指定要扫描的包
//excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
//includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则
public class MainConfig {
@Bean
public GilrFriend gilrFriend(){
return new GilrFriend();
}
/**
* @Bean标注的方法创建对象的时候,方法参数的值从容器中获取
* @param car
* @return
*/
@Bean
public GilrFriend gilrFriend2 (Car car){
GilrFriend gilrFriend = new GilrFriend ();
gilrFriend .setCar(car);
return gilrFriend ;
}
}
测试代码:
public class MainApp {
public static void main(String[] args) {
// ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
// Person bean = (GilrFriend) applicationContext.getBean("gilrFried");
// System.out.println(bean);
// 应用上下文 对比以前xml获取bean的方式。
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Object gilrFried = context.getBean(GilrFriend.class);
System.out.println(gilrFried);
// 打印容器中所有的bean
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
@Scope设置组件作用域
@Lazy-bean懒加载
@Configuration
public class MainConfig2 {
//默认是单实例的
/**
* ConfigurableBeanFactory#SCOPE_PROTOTYPE
* @see ConfigurableBeanFactory#SCOPE_SINGLETON
* @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST request
* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION sesssion
* @return\
* @Scope:调整作用域
* prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。
* 每次获取的时候才会调用方法创建对象;
* singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。
* 以后每次获取就是直接从容器(map.get())中拿,
* request:同一次请求创建一个实例
* session:同一个session创建一个实例
*
* 懒加载:
* 单实例bean:默认在容器启动的时候创建对象;
* 懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化;
*
*/
@Bean(name="girlFriend")
@Scope("singleton")
@Lazy()
public GilrFriend gilrFriend(){
return new GilrFriend();
}
}
测试:
public class MainConfig2Test {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
@Test
public void testScopeAndLazy(){
Object girlFriend = applicationContext.getBean("girlFriend");
System.out.println(girlFriend);
}
}
组件注册-@Conditional-按照条件注册bean
springboot底层大量使用的注解,按照一定的条件判断给容器注册bean。
/**
* ConditionContext:判断条件能使用的上下文(环境)
*
* @See https://www.cnblogs.com/davidwang456/p/4199459.html
* AnnotatedTypeMetadata:定义访问特定类型的注解,不需要加载类。主要方法有:
* 是否有匹配的注解类型
* boolean isAnnotated(String annotationType)
* 获取特定类型注解的属性
* Map<String,Object> getAnnotationAttributes(String annotationType,boolean classValuesAsString)
*/
public class MoneyCondition implements Condition {
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// TODO: 实现自己的逻辑,决定什么条件下注册自己的bean。本例子:有钱注册拜金女
//1、能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
//2、获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
//3、获取当前环境信息
Environment environment = conditionContext.getEnvironment();
BeanDefinitionRegistry registry = conditionContext.getRegistry();
Map<String, Object> annotationAttributes = annotatedTypeMetadata.getAnnotationAttributes("org.springframework.stereotype.Service");
System.out.println("---》"+annotatedTypeMetadata);
System.out.println("是否包含service注解:"+annotatedTypeMetadata.isAnnotated("org.springframework.stereotype.Service"));;
try {
Money bean = conditionContext.getBeanFactory().getBean(Money.class);
if (bean != null) {
return true;
}
} catch (NoSuchBeanDefinitionException e) {
return false;
}
return false;
}
}
com.pc.Config.MainConfig2
/**
* 注释该bean 则拜金女不会注入
* @return
*/
@Bean(name="money")
public Money money(){
return new Money();
}
/**
* 得有钱才行 -->__--> 拜金女
* @return
*/
@Bean(name="拜金女")
@Conditional(MoneyCondition.class)
public GilrFriend gilrFriend3(){
return new GilrFriend("拜金女");
}
测试结果:
在这里插入图片描述
组件注册-@Import-给容器中快速导入一个组件
- 比较简单 不做详细介绍
@Configuration
@Import(Car.class)
public class MainConfig3 {
}
组件注册-@Import-使用ImportSelector
- 示例:
//自定义逻辑返回需要导入的组件
public class CurrentImportSelector implements ImportSelector {
// 返回值,就是到导入到容器中的组件全类名
public String[] selectImports(AnnotationMetadata annotationMetadata) {
boolean annotated = annotationMetadata.isAnnotated("com.pc.Annotation.Register");
// 获取的是@import注解标记的类上所有其他注解
System.out.println("---:"+annotationMetadata.getAnnotationTypes());
if (annotated) {
Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes("com.pc.Annotation.Register");
Boolean value = (Boolean)annotationAttributes.get("value");
if (value) {
return new String[]{"com.pc.Bean.Timer"};
}
}
return new String[0];
}
}
@Configuration
@Import(CurrentImportSelector.class)// 不是注册CurrentImportSelector 而是注册CurrentImportSelector返回的全类型数组
@Register(false)
//@Register 我自己定义的注解 ,true注册组件 false不注册组件
public class MainConfig3 {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Register {
public boolean value() default true;
}
组件注册-@Import-使用ImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata:当前类的注解信息
* BeanDefinitionRegistry:BeanDefinition注册类;
* 把所有需要添加到容器中的bean;调用
* BeanDefinitionRegistry.registerBeanDefinition手工注册进来
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean definition = registry.containsBeanDefinition("com.pc.Bean.Timer");
if(definition){
//指定Bean定义信息;(Bean的类型,Bean。。。)
RootBeanDefinition beanDefinition = new RootBeanDefinition(House.class);
//注册一个Bean,指定bean名
registry.registerBeanDefinition("house", beanDefinition);
}
}
}
@Configuration
@Import({CurrentImportSelector.class,MyImportBeanDefinitionRegistrar.class})
@Register(true)
//@Register 我自己定义的注解 ,true注册组件 false不注册组件
public class MainConfig3 {
}
组件注册-使用FactoryBean注册组件
//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,这个对象会添加到容器中
public Color getObject() throws Exception {
// TODO Auto-generated method stub
System.out.println("ColorFactoryBean...getObject...");
return new Color();
}
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Color.class;
}
//是单例?
//true:这个bean是单实例,在容器中保存一份
//false:多实例,每次获取都会创建一个新的bean;
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
//创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一个Color对象,这个对象会添加到容器中
public Color getObject() throws Exception {
// TODO Auto-generated method stub
System.out.println("ColorFactoryBean...getObject...");
return new Color();
}
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Color.class;
}
//是单例?
//true:这个bean是单实例,在容器中保存一份
//false:多实例,每次获取都会创建一个新的bean;
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
public class MainConfig3 {
@Bean
public ColorFactoryBean colorFactoryBean (){
return new ColorFactoryBean();
}
}
组件注册小结
/**
* 给容器中注册组件;
* 1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
* 2)、@Bean[导入的第三方包里面的组件]
* 3)、@Import[快速给容器中导入一个组件]
* 1)、@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
* 2)、ImportSelector:返回需要导入的组件的全类名数组;
* 3)、ImportBeanDefinitionRegistrar:手动注册bean到容器中
* 4)、使用Spring提供的 FactoryBean(工厂Bean);
* 1)、默认获取到的是工厂bean调用getObject创建的对象
* 2)、要获取工厂Bean本身,我们需要给id前面加一个&
* &colorFactoryBean
*/
生命周期
生命周期-@Bean指定初始化和销毁方法
/**
* bean的生命周期:
* bean创建---初始化----销毁的过程
* 容器管理bean的生命周期;
* 我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
*
* 构造(对象创建)
* 单实例:在容器启动的时候创建对象
* 多实例:在每次获取的时候创建对象\
*
* BeanPostProcessor.postProcessBeforeInitialization
* 初始化:
* 对象创建完成,并赋值好,调用初始化方法。。。
* BeanPostProcessor.postProcessAfterInitialization
* 销毁:
* 单实例:容器关闭的时候
* 多实例:容器不会管理这个bean;容器不会调用销毁方法;
*
*
* 遍历得到容器中所有的BeanPostProcessor;挨个执行beforeInitialization,
* 一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
*
* BeanPostProcessor原理
* populateBean(beanName, mbd, instanceWrapper);给bean进行属性赋值
* initializeBean
* {
* applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
* invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
* applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
*}
*
*
*
* 1)、指定初始化和销毁方法;
* 通过@Bean指定init-method和destroy-method;
* 2)、通过让Bean实现InitializingBean(定义初始化逻辑),
* DisposableBean(定义销毁逻辑);
* 3)、可以使用JSR250;
* @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
* @PreDestroy:在容器销毁bean之前通知我们进行清理工作
* 4)、BeanPostProcessor【interface】:bean的后置处理器;
* 在bean初始化前后进行一些处理工作;
* postProcessBeforeInitialization:在初始化之前工作
* postProcessAfterInitialization:在初始化之后工作
*
* Spring底层对 BeanPostProcessor 的使用;
* bean赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx BeanPostProcessor;
*
*/
BeanPostProcessor 后置处理器
@Component
public class MyBeanPostProcess implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println(s+" MyBeanPostProcess初始化之前....");
return o;
}
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println(s+" MyBeanPostProcess初始化之后");
return o;
}
}
@Configuration
//@Import({CurrentImportSelector.class,MyImportBeanDefinitionRegistrar.class})
//@Register(true)
@ComponentScan("com.pc")
//@Register 我自己定义的注解 ,true注册组件 false不注册组件
public class MainConfig3 {
@Bean
public ColorFactoryBean colorFactoryBean (){
return new ColorFactoryBean();
}
@Bean(initMethod="init",destroyMethod = "destory")
public Sky sky (){
return new Sky();
}
}
测试
@Test
public void testLifeStyle () {
applicationContext.getBean("sky");
// 容器关闭 销毁对象
applicationContext.close();
}
}
init-method PostConstruct postProcessBeforeInitialization 执行顺序:
属性赋值
属性赋值-@Value赋值
属性赋值-@PropertySource加载外部配置文件
@Test
public void testImport () {
/*
* 属性文件中的值在运行时会放入到运行环境变量中
*/
ConfigurableEnvironment environment = applicationContext.getEnvironment();
System.out.println(environment.getProperty("companyName"));//pcgroup
System.out.println(environment.getProperty("location"));//zhongguoguangzhou
}
@Configuration
@PropertySource("company.properties")
public class MainConfig4 {
@Bean
public Company company (){
return new Company();
}
}
company.properties:
companyName=pcgroup
location=zhongguoguangzhou
自动装配-@Autowired&@Qualifier&@Primary
自动装配-@Resource&@Inject
@Resources(JSR250)
@Inject(JSR330,需要导入javax.inject)
自动装配-方法、构造器位置的自动装配
自动装配-Aware注入Spring底层组件
省略…
记录下 EmbeddedValueResolverAware(解析字符串中的占位符)
@Component
public class EmbeddedValueResolverAwarImpl implements EmbeddedValueResolverAware {
StringValueResolver resolver;
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.resolver = resolver;
}
/**
* 将占位符替换为属性文件中的值
*/
public void parse() {
System.out.println(resolver.resolveStringValue("公司名:${companyName} 地址:${location}"));
}
}
自动装配-Aware注入Spring底层原理
自动装配-@Profile原理
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
/**
* The set of profiles for which the annotated component should be registered.
*/
String[] value();
}
class ProfileCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
if (context.getEnvironment() != null) {
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
for (Object value : attrs.get("value")) {
if (context.getEnvironment().acceptsProfiles(((String[]) value))) {
return true;
}
}
return false;
}
}
return true;
}
}