组件注册实现方式
给容器中注册组件;
1)、包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)[自己写的类]
2)、@Bean[导入的第三方包里面的组件]
3)、@Import[快速给容器中导入一个组件]
3.1)、@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
3.2)、ImportSelector:返回需要导入的组件的全类名数组;
3.3)、ImportBeanDefinitionRegistrar:手动注册bean到容器中
4)、使用Spring提供的 FactoryBean(工厂Bean);
4.1)、默认获取到的是工厂bean调用getObject创建的对象
4.2)、要获取工厂Bean本身,我们需要给id前面加一个&(&colorFactoryBean)
1.@Configuration+@Bean给容器当中注册组件
代码实现
@ C o n f i g u r a t i o n : 告 诉 S p r i n g 这 是 一 个 配 置 类 \color{blue}{@Configuration:告诉Spring这是一个配置类} @Configuration:告诉Spring这是一个配置类
@Configuration
public class MainConfig {
/**
* 给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
*/
@Bean("person")
public Person person() {
return new Person("ly", 27);
}
}
@Data
public class Person {
@Value("ly")
private String name;
@Value("#{20-2}")
private Integer age;
@Value("${person.nickName}")
private String nickName;
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
}
测 试 \color{red}{测试} 测试
public class MainTest {
public static void main(String[] args) {
//注解的方式创建一个bean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
Arrays.stream(namesForType).forEach(System.out::println);
}
}
2.@ComponentScan自动扫描组件
代码实现
@Controller
public class BookController {
}
@Service
public class BookService {
}
@Repository
public class BookDao {
}
@Configuration
@ComponentScan(value = "com.ly.springannotation")
public class MainConfig {
}
/**
* @param
* @return void
* @Description: 获取容器当中所有定义bean的名字
* 测试@ComponentScan 包扫描
* @author luoyong
* @create 21:44 2019/12/28
* @last modify by [LuoYong 21:44 2019/12/28 ]
*/
@Test
public void test1() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
//获取容器当中所有定义bean的名字
Arrays.stream(beanDefinitionNames).forEach(System.out::println);
}
excludeFilters()&&includeFilters()
e
x
c
l
u
d
e
F
i
l
t
e
r
s
(
)
:
指
定
扫
描
的
时
候
按
照
什
么
规
则
排
除
那
些
组
件
\color{blue}{excludeFilters() :指定扫描的时候按照什么规则排除那些组件}
excludeFilters():指定扫描的时候按照什么规则排除那些组件
i
n
c
l
u
d
e
F
i
l
t
e
r
s
(
)
:
指
定
扫
描
的
时
候
需
要
包
含
那
些
组
件
默
认
按
照
默
认
的
过
滤
器
扫
描
所
有
这
边
设
置
u
s
e
D
e
f
a
u
l
t
F
i
l
t
e
r
s
=
f
a
l
s
e
\color{blue}{includeFilters() :指定扫描的时候需要包含那些组件 默认按照默认的过滤器 扫描所有 这边设置 useDefaultFilters = false}
includeFilters():指定扫描的时候需要包含那些组件默认按照默认的过滤器扫描所有这边设置useDefaultFilters=false
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照给定的类型}
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.REGEX:使用正则指定
FilterType.CUSTOM:使用自定义规则
按照注解排除某些组件
@Configuration
@ComponentScan(value = "com.ly.springannotation", excludeFilters = {
@Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}),
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {Person.class})
})
public class MainConfig {
}
只注册某些组件
u s e D e f a u l t F i l t e r s 默 认 值 为 t r u e 扫 描 所 有 所 以 要 将 该 值 设 置 为 f a l s e \color{blue}{useDefaultFilters 默认值为true 扫描所有 所以要将该值设置为false} useDefaultFilters默认值为true扫描所有所以要将该值设置为false
@Configuration
@ComponentScan(value = "com.ly.springannotation", includeFilters = {
// @Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
// @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {Person.class}),
@Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}),
}, useDefaultFilters = false)
public class MainConfig {
/**
* 给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
*/
@Bean("person")
public Person person() {
return new Person("ly", 27);
}
}
/**
* @author luoyong
* @Description: MyTypeFilter
* 自定义类型过滤器
* @create 2019-12-28 22:04
* @last modify by [LuoYong 2019-12-28 22:04]
**/
public class MyTypeFilter implements TypeFilter {
/**
* @param metadataReader 读取到的当前正在扫描类的信息
* @param metadataReaderFactory 可以获取到其他任何类的信息
* @return boolean
* @Description:
* @author luoyong
* @create 22:05 2019/12/28
* @last modify by [LuoYong 22:05 2019/12/28 ]
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//1:获取当前类的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//2:获取当前正在扫描类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("---->" + className);
if (className.contains("ers")) {
//过滤规则
return true;
}
return false;
}
}
3.@Import[快速给容器中导入一个组件]
@Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是全类名
代码实现
package com.ly.springannotation.config;
/**
* @author luoyong
* @Description: MainConfig2
* @create 2019-12-28 22:38
* @last modify by [LuoYong 2019-12-28 22:38]
**/
@Conditional({LinuxCondition.class})
@Configuration
//@Import导入组件,id默认是组件的全类名
@Import({Color.class, Red.class})
public class MainConfig2 {
@Bean
public Person person() {
System.out.println("往容器当中添加Person....");
return new Person("张三", 25);
}
/**
* @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
* <p>
* 如果系统是windows,给容器中注册("bill")
* 如果是linux系统,给容器中注册("linus")
*/
@Conditional(WindowsCondition.class)
@Bean("bill")
public Person person01() {
return new Person("Bill Gates", 62);
}
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02() {
return new Person("linus", 66);
}
}
public class Color {}
public class Red {
}
测试
/**
* @param
* @return void
* @Description: 测试给容器当中导入组件
* @author luoyong
* @create 9:48 2019/12/29
* @last modify by [LuoYong 9:48 2019/12/29 ]
*/
@Test
public void testImport() {
//打印当前容器当中注册的bean
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
Arrays.stream(beanDefinitionNames).forEach(System.out::println);
}
ImportSelector:返回需要导入的组件的全类名数组
代码实现
package com.ly.springannotation.config;
/**
* @author luoyong
* @Description: MainConfig2
* @create 2019-12-28 22:38
* @last modify by [LuoYong 2019-12-28 22:38]
**/
@Conditional({LinuxCondition.class})
@Configuration
//@Import导入组件,id默认是组件的全类名
@Import({Color.class, Red.class,MyImportSelector.class})
public class MainConfig2 {
@Bean
public Person person() {
System.out.println("往容器当中添加Person....");
return new Person("张三", 25);
}
/**
* @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
* <p>
* 如果系统是windows,给容器中注册("bill")
* 如果是linux系统,给容器中注册("linus")
*/
@Conditional(WindowsCondition.class)
@Bean("bill")
public Person person01() {
return new Person("Bill Gates", 62);
}
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02() {
return new Person("linus", 66);
}
}
public class MyImportSelector implements ImportSelector {
/**
* @param importingClassMetadata 当前标注@Import注解的类的所有注解信息
* @return
* @Description: 返回值:就是要导入到容器中的组件全类名
* @author luoyong
* @create 10:20 2019/12/29
* @last modify by [LuoYong 10:20 2019/12/29 ]
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//方法的返回值不能为空 否则会报空指针异常
return new String[]{"com.ly.springannotation.bean.Blue", "com.ly.springannotation.bean.Yellow"};
}
}
public class Blue {
}
public class Yellow {
}
测试
@Test
public void testImport() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
//打印当前容器当中注册的bean
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
Arrays.stream(beanDefinitionNames).forEach(System.out::println);
Blue blue = (Blue) applicationContext.getBean(Blue.class);
System.out.println(blue);
}
ImportBeanDefinitionRegistrar:手动注册bean到容器
代码实现
/**
* @author luoyong
* @Description: MainConfig2
* @create 2019-12-28 22:38
* @last modify by [LuoYong 2019-12-28 22:38]
**/
@Conditional({LinuxCondition.class})
@Configuration
//@Import导入组件,id默认是组件的全类名
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {
@Bean
public Person person() {
System.out.println("往容器当中添加Person....");
return new Person("张三", 25);
}
/**
* @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
* <p>
* 如果系统是windows,给容器中注册("bill")
* 如果是linux系统,给容器中注册("linus")
*/
@Conditional(WindowsCondition.class)
@Bean("bill")
public Person person01() {
return new Person("Bill Gates", 62);
}
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02() {
return new Person("linus", 66);
}
}
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* @param importingClassMetadata 当前类的注解信息
* @param registry BeanDefinition注册类
* @return void
* @Description: 把所有需要添加到容器当中bean:调用BeanDefinitionRegistry.registerBeanDefinition手工注册进来
* @author luoyong
* @create 10:36 2019/12/29
* @last modify by [LuoYong 10:36 2019/12/29 ]
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean blueBean = registry.containsBeanDefinition("com.ly.springannotation.bean.Blue");
boolean yellowBean = registry.containsBeanDefinition("com.ly.springannotation.bean.Yellow");
if (blueBean && yellowBean) {
//指定bean的定义信息
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class);
//注册一个bean 并指定bean名
registry.registerBeanDefinition("rainBow", rootBeanDefinition);
}
}
}
public class RainBow {
}
4.FactoryBean Spring提供的工厂bean
代码实现
/**
* @author luoyong
* @Description: 创建一个Spring定义的FactoryBean
* @create 2019-12-29 10:49
* @last modify by [LuoYong 2019-12-29 10:49]
**/
public class ColorFactoryBean implements FactoryBean<Color> {
/**
* @param
* @return
* @Description: 返回一个Color对象,这个对象会添加到容器中
* @author luoyong
* @create 10:52 2019/12/29
* @last modify by [LuoYong 10:52 2019/12/29 ]
*/
@Override
public Color getObject() throws Exception {
System.out.println("ColorFactoryBean...getObject...");
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
/**
* @param
* @return boolean
* @Description: 是否是单例的
* true:bean是单例的 在容器中保存一份
* false:多实例,每次获取都会创建一个新的bean
* @author luoyong
* @create 10:50 2019/12/29
* @last modify by [LuoYong 10:50 2019/12/29 ]
*/
@Override
public boolean isSingleton() {
return true;
}
}
public class Color {
}
/**
* @author luoyong
* @Description: MainConfig2
* @create 2019-12-28 22:38
* @last modify by [LuoYong 2019-12-28 22:38]
**/
@Conditional({LinuxCondition.class})
@Configuration
//@Import导入组件,id默认是组件的全类名
@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {
@Bean
public Person person() {
System.out.println("往容器当中添加Person....");
return new Person("张三", 25);
}
/**
* @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
* <p>
* 如果系统是windows,给容器中注册("bill")
* 如果是linux系统,给容器中注册("linus")
*/
@Conditional(WindowsCondition.class)
@Bean("bill")
public Person person01() {
return new Person("Bill Gates", 62);
}
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02() {
return new Person("linus", 66);
}
/**
* 使用Spring提供的 FactoryBean(工厂Bean)
* 1)、默认获取到的是工厂bean调用getObject创建的对象
* 2)、要获取工厂Bean本身,我们需要给id前面加一个& (&colorFactoryBean)
*
*/
@Bean
public ColorFactoryBean colorFactoryBean() {
return new ColorFactoryBean();
}
}
测试
/**
* @param
* @return void
* @Description: 测试FactoryBean注册bean
* @author luoyong
* @create 9:48 2019/12/29
* @last modify by [LuoYong 9:48 2019/12/29 ]
*/
@Test
public void testFactoryBean() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
System.out.println("FactoryBean...");
Object bean = applicationContext.getBean("colorFactoryBean");
Object bean2 = applicationContext.getBean("colorFactoryBean");
System.out.println("bean的类型:" + bean.getClass());
System.out.println(bean == bean2);
//获取bean工厂本身
Object bean4 = applicationContext.getBean("&colorFactoryBean");
System.out.println(bean4.getClass());
}
其他
设置组件的作用域和懒加载
@Configuration
public class MainConfig2 {
/**
* @param
* @return
* @Description: @Scope 作用域
* prototype:多实例的:ioc容器启动并不会去调用方法创建对象放在容器中。每次获取的时候才会调用方法创建对象;
* singleton:单实例的(默认值):ioc容器启动会调用方法创建对象放到ioc容器中。以后每次获取就是直接从容器(map.get())中拿,
* request:同一次请求创建一个实例
* session:同一个session创建一个实例
* @author luoyong
* @create 22:48 2019/12/28
* @last modify by [LuoYong 22:48 2019/12/28 ]
*/
@Bean
// @Scope("prototype")
@Scope
/**
* 懒加载:针对于单实例bean
* 单实例bean:默认在容器启动的时候创建对象
* 懒加载:容器启动之后不创建对象,第一使用(获取时)Bean时才去创建对象,并进行初始化
*/
// @Lazy
public Person person() {
System.out.println("往容器当中添加Person....");
return new Person("张三", 25);
}
/**
* @param
* @return void
* @Description: 测试@Scope和@Lazy
* @author luoyong
* @create 23:03 2019/12/28
* @last modify by [LuoYong 23:03 2019/12/28 ]
*/
@Test
public void test2() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
//获取容器当中所有定义bean的名字
Arrays.stream(beanDefinitionNames).forEach(System.out::println);
System.out.println("IOC容器创建完成");
//默认作用域是单例的
Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
Person person2 = (Person) applicationContext.getBean("person");
System.out.println(person2);
System.out.println(person == person2);
}
@Conditional根据条件注册bean
代码实现
/**
* @author luoyong
* @Description: MainConfig2
* @create 2019-12-28 22:38
* @last modify by [LuoYong 2019-12-28 22:38]
**/
@Conditional({LinuxCondition.class})
@Configuration
public class MainConfig2 {
/**
* @Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean
* <p>
* 如果系统是windows,给容器中注册("bill")
* 如果是linux系统,给容器中注册("linus")
*/
@Conditional(WindowsCondition.class)
@Bean("bill")
public Person person01() {
return new Person("Bill Gates", 62);
}
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02() {
return new Person("linus", 66);
}
}
public class LinuxCondition implements Condition {
/**
* @param context 判断条件能使用的上下文
* @param metadata 注释信息
* @return boolean
* @Description: 是否linux系统
* @author luoyong
* @create 23:14 2019/12/28
* @last modify by [LuoYong 23:14 2019/12/28 ]
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//1:能获取到ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2:获取类的加载器
ClassLoader classLoader = context.getClassLoader();
//3:获取当前环境
Environment environment = context.getEnvironment();
//4:获取到bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
//可以判断容器当中bean注册的情况 也可以给容器当中注册bean
boolean definition = registry.containsBeanDefinition("person");
if (property.contains("linux")|| property.contains("Mac")){
return true;
}
return false;
}
}
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if (property.contains("Windows")) {
return true;
}
return false;
}
}
/**
* @param
* @return void
* @Description: @Conditional 根据条件注册bean
* @author luoyong
* @create 23:07 2019/12/28
* @last modify by [LuoYong 23:07 2019/12/28 ]
*/
@Test
public void test3() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
//动态获取环境变量的值:Mac OS X
Environment environment = applicationContext.getEnvironment();
String property = environment.getProperty("os.name");
System.out.println("当前环境是:" + property);
System.out.println(environment.getActiveProfiles());
String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
Arrays.stream(beanNamesForType).forEach(System.out::println);
//获取Person.class 类型的所有bean的信息
Map<String, Person> beansOfType = applicationContext.getBeansOfType(Person.class);
System.out.println(beansOfType);
}