SpringFramework:加与不加@Configuration的区别

1 不加@Configuration注解情况1

  • 两个POJO类A和B,注意A和B都没有标注@Component等注解。
  • 配置类App,注意App类并没有标注任何注解。App内部使用@Bean注解标注了两个方法generateA和generateB。
  • 主类Main,我们创建IOC容器时将App.class作为参数传入。

package com.woods.configuration_test;
/**
 * @author woods
 * Created on 2020-08-04
 */
public class A {
	public A() {
		System.out.println("A construction");
	}
}


package com.woods.configuration_test;
/**
 * @author woods
 * Created on 2020-08-04
 */
public class B {
	public B() {
		System.out.println("B construction");
	}
}

package com.woods.configuration_test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author woods
 * Created on 2020-07-04
 */
public class App {
	@Bean
	public B generateB() {
		return new B();
	}

	@Bean
	public A generateA() {
		generateB();
		return new A();
	}
}

package com.woods.configuration_test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author woods
 * Created on 2020-07-04
 */
public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(App.class);
	}
}

上面代码的运行结果如下。可以看到,generateB()方法被调用了两遍。

B construction
B construction
A construction

问题1:App类是SpringIOC容器中的Bean吗?
回答:是的。register(componentClasses)方法将传入的类转化成AnnotatedGenericBeanDefinition并注册到BeanFactory中。


在Main里new AnnotationConfigApplicationContext(App.class);public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		/*
		* 注意,有父类的情况下先调用父类的构造方法
		* 进一步讲,有父类的情况下调用顺序为,
		* 父类的静态代码块(即父类执行类初始化clinit方法),子类静态代码块(clinit方法),父类非静态代码块,父类构造方法,子类非静态代码块,子类构造方法
		* */
		this();
		register(componentClasses);
		refresh();
	}

问题2:是谁处理了@Bean标注的方法?
ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法中,会调用ConfigurationClassParser的processConfigurationClass方法,处理@Bean注解标注的类。

2 不加@Configuration注解情况2

  • 四个POJO类A、B、C和D,其中C标注了@Component注解,C中使用@Bean注解标注了方法generateC。
  • 配置类App,注意App类并没有标注任何注解。App内部使用@Bean注解标注了两个方法generateA和generateB。
  • 主类Main,我们创建IOC容器时将App.class作为参数传入。

package com.woods.configuration_test;
/**
 * @author woods
 * Created on 2020-08-04
 */
public class A {
	public A() {
		System.out.println("A construction");
	}
}


package com.woods.configuration_test;
/**
 * @author woods
 * Created on 2020-08-04
 */
public class B {
	public B() {
		System.out.println("B construction");
	}
}

package com.woods.configuration_test;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 * @author woods
 * Created on 2020-09-11
 */
@Component
public class C {

	public C() {
		System.out.println("C construction");
	}

	@Bean
	public D generateD() {
		return new D();
	}
}

package com.woods.configuration_test;
/**
 * @author woods
 * Created on 2020-09-11
 */
public class D {
	public D() {
		System.out.println("D construction");
	}
}


package com.woods.configuration_test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author woods
 * Created on 2020-07-04
 */
 @ComponentScan("com.woods.configuration_test")
public class App {
	@Bean
	public B generateB() {
		return new B();
	}

	@Bean
	public A generateA() {
		generateB();
		return new A();
	}
}

package com.woods.configuration_test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author woods
 * Created on 2020-07-04
 */
public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(App.class);
	}
}

上面代码的运行结果如下。

C construction
D construction
B construction
B construction
A construction

3 加@Configuration注解

  • 两个POJO类A和B,注意A和B都没有标注@Component等注解。
  • 配置类App,注意App类并没有标注任何注解。App内部使用@Bean注解标注了两个方法generateA和generateB。
  • 主类Main,我们创建IOC容器时将App.class作为参数传入。

package com.woods.configuration_test;
/**
 * @author woods
 * Created on 2020-08-04
 */
public class A {
	public A() {
		System.out.println("A construction");
	}
}


package com.woods.configuration_test;
/**
 * @author woods
 * Created on 2020-08-04
 */
public class B {
	public B() {
		System.out.println("B construction");
	}
}

package com.woods.configuration_test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author woods
 * Created on 2020-07-04
 */
@Configuration
public class App {
	@Bean
	public B generateB() {
		return new B();
	}

	@Bean
	public A generateA() {
		generateB();
		return new A();
	}
}

package com.woods.configuration_test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author woods
 * Created on 2020-07-04
 */
public class Main {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(App.class);
	}
}

上面代码的运行结果如下。

B construction
A construction

问题1:为什么这里只打印了一个B construction?
回答:如果配置类(这里是App类)上加了@Configuration注解,那么Spring会为App类生成cglib代理。在执行App内部@Bean标注的方法时,会先看Bean是否已经存在,如果存在直接从BeanFactory中取出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值