组件的作用域

以前的写法

<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;
}

}

测试类

= 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;
}
}
= 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());
}