@Bean和@Component都是用于创建一个bean实例.
区别于@Component只能定义bean名称,且只能用于类上
//只能用于类上
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
//对于被自动定位转换为spring bean的组件,的逻辑组件名的建议
String value() default "";
}
,这样如果只有@Component ,应用想给jar包中的类创建一个bean给spring管理,就没那么简单了.
而@bean属性更丰富,还可以定义在方法上,这样就填补了@component功能的空白
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
@Deprecated
Autowire autowire() default Autowire.NO;
boolean autowireCandidate() default true;
String initMethod() default "";
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
同时也支持在类被@Configuration注解定义的类中的被@bean定义的方法内,直接调用另一个被@bean注解定义的方法来注入依赖的用法
@Configuration
public class QuartzConfig {
@Bean
MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean() {
MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean();
bean.setTargetClass(CustomNonParamJob.class);
//需要TargetMethod是静态的
bean.setTargetMethod("hello");
return bean;
}
@Bean
SimpleTriggerFactoryBean simpleTriggerFactoryBean() {
SimpleTriggerFactoryBean bean = new SimpleTriggerFactoryBean();
bean.setJobDetail(methodInvokingJobDetailFactoryBean().getObject());
bean.setStartTime(new Date());
bean.setRepeatInterval(2000);
bean.setRepeatCount(3);
return bean;
}
这种用法不会导致破坏单例.
这是因为@bean分为两种模式,一种是@Bean Lite Mode(轻量模式),这种模式下被@bean定义的方法需要在@Component下或者原生类下,效果类似于@Component注册在类上的效果,只是@bean注册在方法上.
@Component
public class Calculator {
public int sum(int a, int b) {
return a+b;
}
@Bean
public MyBean myBean() {
return new MyBean();
}
}
原生类
public class Test {
@Bean
public Custom custom(){
return new Custom();
}
}
@Configuration
@Import(Test.class)
public class QuartzConfig {
这种情况下,这些方法被当做一个普通的工厂方法进行处理
org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory, java.lang.Object, java.lang.reflect.Method, java.lang.Object...)
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Object factoryBean, final Method factoryMethod, Object... args) {
...
Object result = factoryMethod.invoke(factoryBean, args);
...
}
而@Configuration下的@bean被称为是Full mode(完全模式),bean的创建是通过cglib代理生成的被@Configuration定义的类的增强类,因为@Configuration定义的类的bean,默认都是被Spring通过Cglib增强的子类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
/**
* Specify whether {@code @Bean} methods should get proxied in order to enforce
* bean lifecycle behavior, e.g. to return shared singleton bean instances even
* in case of direct {@code @Bean} method calls in user code. This feature
* requires method interception, implemented through a runtime-generated CGLIB
* subclass which comes with limitations such as the configuration class and
* its methods not being allowed to declare {@code final}.
* <p>The default is {@code true}, allowing for 'inter-bean references' via direct
* method calls within the configuration class as well as for external calls to
* this configuration's {@code @Bean} methods, e.g. from another configuration class.
* If this is not needed since each of this particular configuration's {@code @Bean}
* methods is self-contained and designed as a plain factory method for container use,
* switch this flag to {@code false} in order to avoid CGLIB subclass processing.
* <p>Turning off bean method interception effectively processes {@code @Bean}
* methods individually like when declared on non-{@code @Configuration} classes,
* a.k.a. "@Bean Lite Mode" (see {@link Bean @Bean's javadoc}). It is therefore
* behaviorally equivalent to removing the {@code @Configuration} stereotype.
* @since 5.2
*/
org.springframework.context.annotation.Configuration#proxyBeanMethods
boolean proxyBeanMethods() default true;
通过设置proxyBeanMethods = false,可以关闭默认的cglib增强
/**
*Configuration classes must be non-final (allowing for subclasses at runtime),
*unless the proxyBeanMethods flag is set to false in which case no runtime-generated subclass is necessary.
*配置类必须是非final类(允许在运行时生成子类),除非proxyBeanMethods标志被设置为false,在这种情况下不需要运行时生成的子类。
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@Configuration(proxyBeanMethods = false)
public class TestConfig {
{
System.out.println("initTestConfig");
}
}
org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
return BeanUtils.instantiateClass(constructorToUse);
}
否则TestConfig的创建会经过Cglib的增强
@Configuration
public class TestConfig {
{
System.out.println("initTestConfig");
}
}
在这种被增强的情况下,内部依赖注入通过调用方法的方式实现还能保证单例,依赖的就是org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor#intercept
org.springframework.context.annotation.ConfigurationClassEnhancer.BeanMethodInterceptor#intercept
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
// It is a candidate FactoryBean - go ahead with enhancement
//如果是一个工厂bean,则继续通过Cglib增强
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
// The factory is calling the bean method in order to instantiate and register the bean
// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
//工厂bean正在调用bean方法来实例化和注册bean,这时调用原本的工厂bean创建bean的方法,也就是被增强类的父类的方法
// create the bean instance.
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
//如果是普通的bean且已经创建了
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
ConfigurableBeanFactory beanFactory, String beanName) {
// The user (i.e. not the factory) is requesting this bean through a call to
// the bean method, direct or indirect. The bean may have already been marked
// as 'in creation' in certain autowiring scenarios; if so, temporarily set
// the in-creation status to false in order to avoid an exception.
//是否早已创建
boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
也就是调用的被代理的方法,而不是原本的方法,所以不会出现创建多次的现象