@Bean和@Component

@Bean和@Component在Spring中用于创建bean实例,@Component主要在类级别定义bean,功能较为简单;@Bean则功能更丰富,可在方法上使用,允许在@Configuration注解的类中通过方法调用来注入依赖,确保单例不被破坏。@Bean有两种模式:Lite Mode和Full Mode,Full Mode通过Cglib代理确保依赖注入时保持单例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

也就是调用的被代理的方法,而不是原本的方法,所以不会出现创建多次的现象

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值