@Bean
结合使用 @Component
的作用,将当前类注入ioc容器 value
属性,指定注入ioc容器的名称,默认是类名首字母小写 @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {}
/**
* 配置类
*/
@Configuration(value = "MyConfiguration")
public class MyConfiguration{
/**
* 注入一个User对象,ioc容器中的name是user,类型是User类型
*/
@Bean
public User user(){
return new User(1,"name");
}
}
name
:指定注入ioc容器中的名称 value
:同name autowireCandidate
:是否能够自动注入,默认是true,如果指定了属性为false,那么不能使用 @Autowired
或者 @Resource
自动注入 initMethod
:指定初始化方法,在构造方法之后执行 destroyMethod
:指定销毁方法,在容器关闭的时候执行 /**
* 配置类
*/
@Configuration(value = "MyConfiguration")
public class MyConfiguration{
/**
* 注入一个User对象,ioc容器中的name是user,类型是User类型
* init是User类中的init方法,destory是User类中的destory方法
*/
@Bean(initMethod = "init",destroyMethod = "destory")
public User user1(){
return new User(1,"name");
}
}
/**
* User类
*/
public class Userimplements Serializable{
private Integer id;
private String name;
public User(String name){
this.name = name;
}
public User(Integer id, String name){
System.out.println("执行构造方法");
this.id = id;
this.name = name;
}
public void init(){
System.out.println("初始化方法");
}
public void destory(){
System.out.println("销毁方法");
}
}
singleton prototype request session
/**
* 指定多实例,每次用到都会调用
*/
@Bean(initMethod = "init",destroyMethod = "destory")
@Scope(value = "prototype")
public User user1(){
return new User(1,"name");
}
Condition
数组,要向实现相应的功能,可以自定义一个类,实现 Condition
这个接口即可。 这个注解在SpringBoot中将会有很多的扩展,这里就不多说了。
/**
* 指定多实例,每次用到都会调用
* @Conditional 只有里面全部都匹配才会正常注入到容器中
*/
@Bean(initMethod = "init",destroyMethod = "destory")
@Conditional(value = {FirstCondition.class})
public User user1(){
return new User(1,"name");
}
下面看看 FirstCondition
这个类具体实现
matches
方法即可,返回true表示符合条件,否则不满足条件,只有满足条件才会注入到ioc容器中 /**
* 自定义的条件判断,实现Condition接口
*/
public class FirstConditionimplements Condition{
/**
* 如果返回true表示符合条件,反之不符合条件
* @param context ConditionContext对象,可以获取上下文的信息
* @param metadata AnnotatedTypeMetadata对象,可以获取标注在该方法上面的注解信息
* @return
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata){
//获取Environment,用来获取运行环境中的一些变量
Environment environment = context.getEnvironment();
//获取在properties文件中配置的参数,表示是否注入相关属性
Boolean isAutowired = environment.<Boolean>getProperty("isAutowired", Boolean.class);
return isAutowired;
}
}
public interface ConditionContext{
/**
* 获取 BeanDefinitionRegistry,可以自己手动注册对象到ioc容器中
*/
BeanDefinitionRegistrygetRegistry();
/**
* 获取BeanFacotory,操作ioc容器,比如获取对应的Bean,判断ioc中是否已经注入
*/
@Nullable
ConfigurableListableBeanFactorygetBeanFactory();
/**
* 返回当前的运行环境,可以获取运行环境中的一下参数,或者一些配置文件中的数据
*/
EnvironmentgetEnvironment();
/**
* 获取资源加载器
*/
ResourceLoadergetResourceLoader();
/**
* 获取类加载器
*/
@Nullable
ClassLoadergetClassLoader();
}
@Conditional
这个注解的方法上的注解和对应的参数等信息 public interface AnnotatedTypeMetadata{
/**
* 判断方法上是否有对应的注解
* @param annotationName 注解类的全类名,getName()
*/
boolean isAnnotated(String annotationName);
/**
* 获取对应注解的全部属性的值,key是属性,value是属性的值
* @param annotationName 注解类的全类名,getName()
*/
@Nullable
Map<String, Object>getAnnotationAttributes(String annotationName);
@Nullable
Map<String, Object>getAnnotationAttributes(String annotationName,boolean classValuesAsString);
@Nullable
MultiValueMap<String, Object>getAllAnnotationAttributes(String annotationName);
@Nullable
MultiValueMap<String, Object>getAllAnnotationAttributes(String annotationName,boolean classValuesAsString);
}
@Bean
中的 init-menthd
指定的作用相同 @PostConstruct
public void init(){
System.out.println("初始化方法");
}
@Bean
中的 destroy-method
属性 @PreDestroy
public void destory(){
System.out.println("销毁方法");
}
value
属性中指定需要导入的类即可,如下: @Configuration(value = "MyConfiguration")
@Import(value = {Person.class})
public class MyConfiguration{}
新建一个配置类,但是不用 @Configuration
标注,使用 @Import
在另外一个配置类上引入即可
/**
* 这是一个配置,但是并没有使用@Configuration这个注解,因此不会生效
*/
public class SecondConfiguration{
@Bean
public Person person(){
return new Person();
}
}
在另外一个配置类使用 @Import
注解引入上面的配置类,如下:
@Configuration(value = "MyConfiguration")
@Import(value = {SecondConfiguration.class})
public class MyConfiguration{}
使用ImportSelector需要自定义一个实现类,如下:
/**
* 自定义Selector,需要实现ImportSelector
*/
public class FirstSelectorimplements ImportSelector{
/**
* 筛选逻辑,返回的是String数组(需要注入到容器中的类的全类名)
* @param importingClassMetadata AnnotationMetadata对象,对标注了@Import这个注解的类中的所有注解信息,比如获取标注指定注解的方法
* @return 返回的是需要注入的字符串数组(类的全类名)
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//获取@Import标注的类中被@Bean标注的方法元数据
Set<MethodMetadata> annotatedMethods = importingClassMetadata.getAnnotatedMethods(Bean.class.getName());
annotatedMethods.forEach(o->{
System.out.println(o.getMethodName());
});
//将Person类返回去,那么将会自动注入Person
return new String[]{Person.class.getName()};
}
}
在配置类上使用 @Import
注解引入即可,如下:
@Configuration
@Import(value = {FirstSelector.class})
public class MyConfiguration{}
public interface AnnotationMetadataextends ClassMetadata,AnnotatedTypeMetadata{
//拿到Class上标注的所有注解,依赖于Class#getAnnotations
Set<String>getAnnotationTypes();
// 拿到所有的元注解信息AnnotatedElementUtils#getMetaAnnotationTypes
//annotationName:注解类型的全类名
Set<String>getMetaAnnotationTypes(String annotationName);
// 是否包含指定注解 (annotationName:全类名)
boolean hasAnnotation(String annotationName);
//这个厉害了,依赖于AnnotatedElementUtils#hasMetaAnnotationTypes
boolean hasMetaAnnotation(String metaAnnotationName);
// 类里面只有有一个方法标注有指定注解,就返回true
//getDeclaredMethods获得所有方法, AnnotatedElementUtils.isAnnotated是否标注有指定注解
boolean hasAnnotatedMethods(String annotationName);
// 注意返回的是MethodMetadata 原理基本同上
// .getDeclaredMethods和AnnotatedElementUtils.isAnnotated 最后吧Method转为MethodMetadata
Set<MethodMetadata>getAnnotatedMethods(String annotationName);
}
需要自定义一个类实现 ImportBeanDefinitionRegistrar
,如下:
/**
* 自定义的FirstBeanDefinitionRegistrar,需要实现ImportBeanDefinitionRegistrar
*/
public class FirstBeanDefinitionRegistrarimplements ImportBeanDefinitionRegistrar{
/**
* 自己手动注册Bean到ioc容器中
* @param importingClassMetadata 获取@Import标注的类上的注解信息,比如获取被指定注解标注的方法信息
* @param registry 注册中心,可以获取指定bean的信息和手动注册bean
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){
//如果容器中没有Person这个Bean,就创建一个
if (!registry.containsBeanDefinition(Person.class.getName())){
GenericBeanDefinition beanDefinition=new GenericBeanDefinition();
beanDefinition.setBeanClass(Person.class);
//手动注册
registry.registerBeanDefinition("person",beanDefinition);
}
}
}
在配置类上使用 @Import
注解引入即可,如下:
@Configuration
@Import(value = {FirstBeanDefinitionRegistrar.class})
public class MyConfiguration{}
@Bean
,另外一种是结合 @Service,@Component,@Controller.....
@Bean
@Primary
public User user1(){
return new User(1,"user1");
}
//第二种
@Primary
@Component
public class Person{
private String name;
private Integer age;
}
@Controller
public class UserController{
@Autowired
private UserService userService;
required
:指定该属性是否是必须的,默认为true,表示一定要为属性赋值,如果ioc容器中没有对应的Bean,那个将会报错,如果为false,会先从ioc容器中查找对应的Bean,如果存在就进行赋值,不存在就不赋值,不会报错。 @Autowired
结合使用,用来从容器中注入指定名字的Bean @Autowired
就不太适用了,此时就要结合该注解,指定需要注入的name。(当然除了 @Autowired
还是可以根据成员变量的名称进行注入的) @Controller
public class UserController{
@Autowired
@Qualifier(value = "userService")
private UserService userService;
@Component
@PropertySource(value = {"classpath:user.properties"})
public class Userimplements Serializable{
private String name;
private Integer age;
public User(){}
public User(String name, Integer age){
this.name = name;
this.age = age;
}
value ignoreResourceNotFound
${}
的方式获取配置文件中设置的值 @Value("${name}")
private String name;
value
属性可以是自己随便指定的值,如下: @Value("陈加兵")
private String name;