Does spring always ensure same creation order for independent beans? - spring

Let's say, I have 4 beans like,
#Component
public class Bean11 {
#PostConstruct
public void post(){
System.out.println("I am bean # 1");
}
}
#Component
public class Bean2 {
#PostConstruct
public void post(){
System.out.println("I am bean # 2");
}
}
#Component
public class Bean3 {
#PostConstruct
public void post(){
System.out.println("I am bean # 3");
}
}
#Component
public class Bean4 {
#PostConstruct
public void post(){
System.out.println("I am bean # 4");
}
}
none of these are dependent on each other. Will their creation always be in the same order or will spring just randomly instantiate them?

Related

Invoking PostConstruct for each bean in a list

I have the following pseudo code:
#Bean
public List<BeanB> beanB(
List<BeanA> beansA) {
List<BeanB> beansB = new ArrayList<>();
for (BeanA beanA : beansA) {
beansB.add(new BeanB(beanA))
}
return beansB;
}
#Bean
public BeanC beanC(
List<BeanB> beansB) {
return new BeanC(beansB);
}
Now the challenge is when the list of BeansB is constructed post construct is not invoked on those beans in the list. Is there any idiomatic way to trigger post construct invocation on those beans.
This does not work well as #PostConstruct is called by Spring. and from your code, for List<BeanB>, Spring will only try to find #PostConstruct in List. If it can find it, it will execute the #PostConstruct code.
I suspect you are writing beanA as follow in case you have #PostConstruct in beanA's class like below.
#Bean
public BeanA beanA_1() {
return new BeanA();
}
#Bean
public BeanA beanA_2() {
return new BeanA();
}
// which naming List of Bean B as beanB does not seems a good idea though
#Bean
public List<BeanB> beanB(List<BeanA> beansA) {
List<BeanB> beansB = new ArrayList<>();
for (BeanA beanA : beansA) {
beansB.add(new BeanB(beanA))
}
return beansB;
}
To make it work, there are multiple ways, I will just suggests some of them.
Creating a new Class, says BeanBCollectionWrappe to wrap the List of BeanB. And to make the code a bit more robust, I am implementing InitializingBean instead of #PostConstruct which is essentially the same, but allow me to ensure the method is afterPropertiesSet but not any methods.
public class BeanBCollectionWrapper implements InitializingBean {
private List<BeanB> beansB;
public void afterPropertiesSet() throws Exception {
for (BeanB beanB: beansB) {
beanB.afterPropertiesSet();
}
}
// getter and setter
}
public class BeanB implements InitializingBean {
public void afterPropertiesSet() throws Exception {
// ...
}
}
The Wrapper code can definitely be a bit better by use of Generics, like replacing BeanB to <T extends InitializingBean>.
And for the last Part,
#Bean
public BeanC beanC(BeanBCollectionWrapper wrapper) {
return new BeanC(wrapper.getBeansB());
}
Another method can be done by implementing BeanPostProcessor.
For example,
#Component
public class BeanBListBeanPostProcessor implements BeanPostProcessor{
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("beanB")) {
List<BeanB> beanBList = (List) bean;
for (BeanB beanB : beanBList) {
try {
beanB.afterPropertiesSet();
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
return null;
}
}
public class BeanB implements InitializingBean {
public void afterPropertiesSet() throws Exception {
// ...
}
}

Spring: Publishing event from InitializingBean's afterPropertiesSet method does NOT work

Recently I have found that when I publish an event from org.springframework.beans.factory.InitializingBean.afterPropertiesSet(), then it is unable to publish that event!
However this very same event trigger gets invoked if I invoke it from #Controller or any other class class (the event invocation mechanism remains same for both places).
I have put a print statement after publishing event in InitBean ('Trigger done') and that is successfully printed too.
If you have any idea about this behaviour then please let me know.
Thanks very much
//Sample code for InitializingBean:
#Component
public class InitBean implements InitializingBean {
private final ApplicationEventPublisher publisher;
public InitBean(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
#Override
public void afterPropertiesSet() throws Exception {
this.publisher.publishEvent(new TriggerEvent());
System.out.println("Trigger done");
}
}
// Sample code for trigger event:
public class TriggerEvent extends ApplicationEvent {
public TriggerEvent() {
super("source");
}
}
// Sample code for listener:
#Component
public class TriggerListener {
#EventListener(TriggerEvent.class)
public void trigger(TriggerEvent triggerEvent) {
System.out.println("Trigger event has come");
}
}
Without testing, I think the problem is that afterPropertiesSet is just too early in the Spring Bean live cycle.
Try firing the event a little later.
Rather in a #PostConstruct, an init-method, or when the application context refresh event was catched.
#PostConstruct:
#Component
public class InitBean {
...
#PostConstruct
public void fire() throws Exception {
this.publisher.publishEvent(new TriggerEvent());
System.out.println("Trigger done");
}
}
init-method:
#Configuration
public class AppConfig {
#Bean(initMethod="fire")
public InitBean initBean (ApplicationEventPublisher publisher) {
return new InitBean (publisher);
}
}
public class InitBean {
...
#PostConstruct
public void fire() throws Exception {
this.publisher.publishEvent(new TriggerEvent());
System.out.println("Trigger done");
}
}
context refresh way
#Component
public class InitBean {
...
#EventListener
public void onApplicationEvent(ContextRefreshedEvent event) {
fire();
}
public void fire() throws Exception {
this.publisher.publishEvent(new TriggerEvent());
System.out.println("Trigger done");
}
}
I don't know if the first two approaches solve the suspected problem, but the last one should work.

Spring configuration - Autowired bean required?

I have the situation where a protoype bean contains a singleton bean. In order to achieve it, I had to create 2 configuration classes. Is it possible to merge my 2 confgiuration classes into a single one?
Singleton class:
public class MySingleton {
}
Prototype class:
public class MyPrototype {
private MySingleton b;
public MyPrototype(MySingleton b) {
this.b = b;
}
}
Configuration class 1:
#Configuration
public class ConfigClassA {
#Bean
public MySingleton myBean() {
return new MySingleton();
}
}
Configuration class 2:
#Configuration
public class ConfigClassB {
#Autowired
public MySingleton mb;
#Bean
#Scope("prototype")
public MyPrototype myPrototype() {
return new MyPrototype(mb);
}
}
Try this:
#Configuration
public class ConfigClass {
#Bean
public MySingleton myBean() {
return new MySingleton();
}
#Bean
#Scope("prototype")
public MyPrototype myPrototype(MySingleton myBean) {
return new MyPrototype(myBean);
}
}
The BeanFactory should search for a bean of type MySingleton when creating the prototype bean and inject it into the method myPrototype.

#Before #PostConstruct Spring AOP ineterception

I'm trying to write an aspect that can intercept PostConstruct methods. I've looked at related questions on SO and others, and following them, this is what I have so far:
The Spring configuration
#Configuration
#EnableAspectJAutoProxy
#EnableLoadTimeWeaving
#...//other config annotations
public class WebConfiguration {
#Bean
public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
return new CommonAnnotationBeanPostProcessor();
}
... // etc
}
The annotation:
#Retention(RetentionPolicy.RUNTIME)
public #interface Secured {
Permission[] permissions() default {};
}
The bean
#Component
#Scope("request")
public class SomeWebBean {
#Secured(permissions = Permission.SOME_PERMISSION)
#PostConstruct
public void secure() {
... // some stuff
}
}
The aspect
#Component
#Aspect
public class SecuredAspect {
#Before("#annotation(secured)")
public void doAccessCheck(Secured secured) {
... // actually do the access check
}
}
If I call someWebBean.secure() from a page, then the aspect is invoked. However, it is not invoked on bean creation.
So as a note to future me - this absolutely cannot be done in this way using Spring AOP.
However, the same effect can be achieved by implementing a BeanPostProcessor as below:
public class SecureBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
Secured secured = bean.getClass().getAnnotation(Secured.class);
if (secured != null) {
// do your security test here, throw an exception, return false, however you like
}
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
You can extend CommonAnnotationBeanPostProcessor and override postProcessBeforeInitialization(Object bean, String beanName)
Then register replace the original CommonAnnotationBeanPostProcessor with a BeanFactoryPostProcessor .
public class InitCommonAnnotationBeanPostProcessor extends CommonAnnotationBeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return super.postProcessBeforeInitialization(bean, beanName);
}
}
public class InitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
RootBeanDefinition def = new RootBeanDefinition(InitCommonAnnotationBeanPostProcessor.class);
def.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME, def);
}
}
#Configuration
public class InitialisationMonitoringConfig {
public static final String BEAN_INIT_MONITOR = "BEAN_INIT_MONITOR";
#Bean
public static InitBeanFactoryPostProcessor initBeanFactoryPostProcessor() {
return new InitBeanFactoryPostProcessor();
}
}
This is ugly, but I had to do that to analyse startup times in dev environment.
Maybe it's enough to just declare InitCommonAnnotationBeanPostProcessor as a bean, I didn't tried.

Javaconfig bean overiding does not take in account added #DependsOn

While overrding a Javaconfig Bean by extending the original #Configuration class, I would like to add a #DependsOn for the new Bean definition.
However, this depends-on seems not to be taken in account. here is a TestCase reproducing my issues:
public class SpringTest {
#Test
public void testDependsOnTakenInAccount() {
AnnotationConfigApplicationContext ctx2 = new AnnotationConfigApplicationContext(AConfig.class, CConfig.class);
Assert.assertEquals("overriden", ctx2.getBean("bean"));
}
#Configuration
public static class AConfig {
#Bean
public Object bean() {
return "not overriden";
}
}
#Configuration
public static class CConfig extends AConfig {
protected boolean isInitialized = false;
#Bean
public Void doInit() {
isInitialized = true;
return null;
}
#Bean
#DependsOn("doInit")
public Object bean() {
if (!isInitialized) {
throw new RuntimeException("Not initialized");
}
return "overriden";
}
}
}
Is this an expected behavior? If yes, how can I add dependency while overriding a bean?
For me seems like a bug.
When overriding a #Bean factory method in a Configuration class, the parent BeanDefinition wins and get registered on the BeanFactory overriding the child one.
So you cannot configure the bean with annotaions (because it will be overriden).
The following Test result on
expected:<[doInit]> but was:<[otherBean]>
#RunWith(JUnit4ClassRunner.class)
public class DependOnTest {
#Test
public void testBeanDefinitionOverriding() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
BeanDefinition bd = ctx.getBeanDefinition("bean");
Assert.assertEquals("doInit", bd.getDependsOn()[0]);
}
#Configuration
public static class ParentConfig {
#Bean
#DependsOn("otherBean")
public String bean() {
return "not overriden";
}
#Bean
public String otherBean() {
return "otherBean";
}
}
#Configuration
public static class Config extends ParentConfig {
#Bean
public String doInit() {
return "doInit";
}
#Bean
#DependsOn("doInit")
public String bean() {
return "overriding";
}
}
}
I think that problem start on ConfigurationClassParser:
// recursively process the configuration class and its superclass hierarchy
do {
metadata = doProcessConfigurationClass(configClass, metadata);
}
while (metadata != null);
That result on overriden method added to CongurationClass.beanMethods
It could be fixed checking if the beanMethod was already added from a superclass in ConfigurationClass.addBeanMethod()
public void addBeanMethod(BeanMethod method) {
// Check if already added a bean method from superclass
for (BeanMethod beanMethod : beanMethods) {
if (beanMethod.getMetadata().getMethodName().equals(method.getMetadata().getMethodName()) &&
!(beanMethod.getMetadata().getDeclaringClassName()).equals(method.getMetadata().getDeclaringClassName()))
// log and return.
return;
}
this.beanMethods.add(method);
}
As pointed out by Jose Luis Martin, this has been confirmed as a bug by Spring team.
I've workarounded it with:
#DependsOn("doInit")
#Bean
public Void notOverridingBean() {
return null;
}
#Bean
public Object bean(Object notOverridingBean) {
return "overriden";
}
an alternative is to override the bean in another #Configuration class.

Resources