spring注解驱动(组件注册):组件的作用域,懒加载,按照条件注册bean,给容器导入组件方式

组件的作用域

以前的写法

	<bean id="person" class="jane.bean.Person" scope="singleton">
		<property name="name" value="张三"></property>
		<property name="age" value="18"></property>
	</bean>

现在的写法

在配置类里面的方法写

	/*
	 * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
	 * @see ConfigurableBeanFactory#SCOPE_SINGLETON
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
	 * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
	 * 分别对应:
	 * "prototype"	多实例的	,ioc容器启动的时候不会调用方法创建对象放在容器中
	 * 				而是每次获取的时候才会调用方法创建对象
	 * "singleton"	单实例的(默认值),ioc容器启动会调用方法创建对象放到ioc容器中
	 * 				以后每次获取就是直接从容器中拿出来
	 * "request"	同一次请求创建一个实例
	 * "session"	同一个session创建一个实例
	 */
	@Scope("prototype")
	@Bean(value = "person2")
	public Person person2()
	{
    
    
		return new Person("张三", 18);
	}

懒加载

	/* 懒加载:
	 * 		针对的是单实例bean,默认在容器启动的时候创建对象
	 * 		而懒加载就是容器启动的时候不创建单实例对象,
	 * 			而是在第一次获取bean时候创建对象并且初始化
	 * 		直接在方法里面加上@Lazy就可以了
	 */
	@Lazy
	@Scope("singleton")
	@Bean(value = "person2")
	public Person person2()
	{
    
    
		return new Person("张三", 18);
	}

按照条件注册bean

配置类

package jane.config;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import jane.bean.Person;
import jane.condition.LinuxCondition;
import jane.condition.WindowsCondition;
//放在类上面,就是对类中的组件进行统一的设置,满足这个条件的类才能被注册进去
//@Conditional({WindowsCondition.class})
@Configuration
public class MyConfig2
{
    
    
	/*
	 * @Conditional({})按照一定的条件进行判断,满足条件的bean才会注册到容器里面
	 * 点进去查看@Target({ElementType.TYPE, ElementType.METHOD})
	 * 说明这个注解可以标注在类上,也可以标注在方法上面
	 * 标注在类上的话就是这个类里面所有的方法注册的bean都需要满足这个条件才能被加载进去
	 * 
	 * {}里面写的是Class<? extends Condition>[] value();
	 * Condition的实现类
	 * 
	 * 现在想这样,
	 * 		如果是Windows系统就给容器注册bill
	 * 		如果是Linux系统,就给容器注册linus
	 * 测试的时候
	 * 		run configurations-->VM argument里面写入参数-Dos.name=linux就行
	 */
	@Conditional({
    
    WindowsCondition.class})
	@Bean("bill")
	public Person person1()
	{
    
    
		return new Person("bill gates", 45);
	}
	
	@Conditional({
    
    LinuxCondition.class})
	@Bean("linus")
	public Person person2()
	{
    
    
		return new Person("linus", 32);
	}
}

Condition实现类

package jane.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;

//判断系统是否是Linux
public class LinuxCondition implements Condition
{
    
    
	/*
	 * ConditionContext:判断条件能使用的上下文,比如现在想使用的操作系统名称
	 * AnnotatedTypeMetadata:注释信息
	 */
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
	{
    
    
		//获取ioc容器使用的beanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		//获取类加载器
		ClassLoader classLoader = context.getClassLoader();
		//获取当前的环境信息
		Environment environment = context.getEnvironment();
		//获取bean定义的注册类,里面可以注册一个bean,也可以移除bean
		BeanDefinitionRegistry registry = context.getRegistry();
		
		String property = environment.getProperty("os.name");
		if(property.contains("linux"))
		{
    
    
			return true;
		}
		return false;
	}

}

package jane.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

//判断系统是否是Windows
public class WindowsCondition implements Condition
{
    
    
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
	{
    
    
		if(context.getEnvironment().getProperty("os.name").contains("Windows"))
		{
    
    
			return true;
		}
		return false;
	}

}

测试类

	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);

	@Test
	public void test2()
	{
    
    
		String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
		for (String string : namesForType)
		{
    
    
			System.out.println(string);
		}
		
		Map<String, Person> map = applicationContext.getBeansOfType(Person.class);
		System.out.println(map);
		//可以获取环境的信息,比如获取当前的系统是什么
		ConfigurableEnvironment environment = applicationContext.getEnvironment();
		String property = environment.getProperty("os.name");
		System.out.println(property);
	}

给容器导入组件方式

	/*
	 * 给容器注册组件的方式:
	 * 1. 包扫描+组件注解(@Controller,@Service,@Repository,@Component)
	 * 	  局限于只能导入自己写的类
	 * 2. @Bean(可以导入第三方包的组件)
	 * 3. @Import(快速给容器中导入组件),也可以写多个({})
	 * 	 有三种方式导入
	 * 		{@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
	 * 		1)@Import(要导入到容器中的组件):容器中就会自动注册这个组件
	 * 				id默认是全类名
	 * 		2)ImportSelector:返回需要导入的组件的全类名数组,这个类需要实现implements ImportSelector
	 * 		  这个首先是在配置类的@Import({})里面写上实现了ImportSelector的类
	 * 		  然后再在ImportSelector里面写上返回的数组
	 * 		3)ImportBeanDefinitionRegistrar:也是写一个ImportBeanDefinitionRegistrar的实现类
	 * 			然后将实现类放在@Import里面就行,ioc就会注册实现类要注册的bean
	 * 4. 使用Spring提供的FactoryBean(工厂bean)
	 * 	  需要写FactoryBean<T>的实现类,然后将工厂加入到容器中,
	 * 	  但是真正到容器的是工厂getObject方法返回的对象
	 * 		1.默认获取到的是工厂bean调用getobject创建的对象
	 * 		2.要获取工厂bean本身,我们需要在id前面加一个&
	 */

上面第三个方法写的实现类如果想生效,都必须在配置类写上
@Import({Person.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})

package jane.condition;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

//这里定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector
{
    
    
	/*
	 * 返回值是要导入到容器中的组件的全类名,不能返回null,不然报空指针异常,因为后面会调用
	 * AnnotationMetadata:当前标注@Import注解的类的所有注解信息
	 */
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata)
	{
    
    
		return new String[] {
    
    "jane.config.MyTypeFilter"};
	}

}

package jane.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 jane.bean.Person;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar
{
    
    
	/*
	 * AnnotationMetadata:当前类的注解信息
	 * BeanDefinitionRegistry:bean定义注册类
	 * 		把所有需要添加到容器中的bean,调用registerBeanDefinition手动注册进去
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
	{
    
    
		//指定bean定义信息
		RootBeanDefinition beanDefinition = new RootBeanDefinition(Person.class);
		//注册一个bean,指定bean名称
		registry.registerBeanDefinition("registerBean", beanDefinition);
	}

}

工厂bean的方法

package jane.bean;

import org.springframework.beans.factory.FactoryBean;

//创建一个spring定义的factorybean
public class PersonFactoryBean implements FactoryBean<Person>
{
    
    
	//返回的对象被添加到容器中
	@Override
	public Person getObject() throws Exception
	{
    
    
		return new Person("简", 18);
	}

	@Override
	public Class<?> getObjectType()
	{
    
    
		return Person.class;
	}
	//是否单例,true是单例,false是多例
	@Override
	public boolean isSingleton()
	{
    
    
		return true;
	}
}

	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
	@Test
	public void test3()
	{
    
    
		printBeans();
		//输出结果:工厂bean的类型class jane.bean.Person
		Object bean = applicationContext.getBean("PersonFactoryBean");
		System.out.println("工厂bean的类型"+bean.getClass());
		
		/*
		 * 输出结果:工厂class jane.bean.PersonFactoryBean
		 * 在BeanFactory里面定义好String FACTORY_BEAN_PREFIX = "&";
		 * 表示在id前面加上&就是工厂本身
		 */
		Object bean2 = applicationContext.getBean("&PersonFactoryBean");
		System.out.println("工厂"+bean2.getClass());
	}

猜你喜欢

转载自blog.csdn.net/qq_43416157/article/details/108250148