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