I'm trying to understand where is the right place to put #EnableTransactionManagement annotation in case of multiple JavaConfig contexts?
Consider following scenario: I have JPA config in JPAConfig.java and AppConfig.java with set of service beans. Then I compose overall application config in RootConfig.java.
I define transaction manager within JPAConfig.java as well as enable scanning for JPA repositories - as those expose transactional behavior, I put #EnableTransactionManagement over JPAConfig and it works.
However, some of service beans also need to have transactional methods e.g. accessing several repositories within single transaction. Should I also put #EnableTransactionManagement over AppConfig as well? Looking into implementation of this annotation is seems to me that such approach would cause redefinition of some beans. And actually doing so doesn't seem to work for me.
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories("com.mypackage.repositories")
public class JPAConfig {
// ... here are EntityManager and PlatformTransactionManager beans
}
#Configuration
#ComponentScan("com.mypackage.services")
// #EnableTransactionManagement // - ???
public class AppConfig {
}
#Configuration
#Import({AppConfig.class, JPAConfig.class})
public class RootConfig {
}
Appreciate any advices.
After some experiments I seem to have found the answer myself:
There is no need to configure #EnableTransactionManagement on each
piece of context configuration although it does matter how early this
annotation is discovered as it registers internalTransactionAdvisor
which actually processes #Transactional annotations on created beans.
In my case, I changed the order of contexts in #Import declaration so
that PersistenceConfig that holds #EnableTransactionManagement is the
first. After this beans from other pieces can use AOP declarative
transaction.
Another caveat relates to simultaneous use of #EnableTransactionManagement and #EnableGlobalMethodSecurity. Global method security uses bean post processing which seems to require whole security configuration to be wired. BeanPostProcessors are created early on context start-up so you can't use declarative #Transactional in any bean that would be needed to bootstrap spring security (in my case UserDetailsContextMapper) - advisor is not yet created then!
Related
I have such app conf in, jar which will be added to the classpath after startup:
#Configuration
#ComponentScan("com.transportexchangegroup.testConf")
public class AppConf {
}
How to load beans dynamically? I saw solutionsm when it is required to write and add bean definitions, but if we do not know everything about new beans and just want to load them automatically?
Class conf = jarService.loadClass("com.x.testConf.AppConf");
((AnnotationConfigServletWebServerApplicationContext) applicationContext).register(conf);
((AnnotationConfigServletWebServerApplicationContext) applicationContext).refresh();
As I see, refresh() turns off web app started locally from IDE.
Do you know any other solutions or what is wrong? Will this work for spring rest controllers from jar?
I'm not sure what do you mean "dynamically".
In general you can load beans if some condition applies, usually depending on the configuration. So you can do something like this:
application.properties: // or yaml it doesn't matter
feature.enabled=true
#Component
#ConditionalOnProperty(name="feature.enabled", havingValue="true", matchIfMissing="true" / "false") // matchIfMissing depends on whether you want the bean to be loaded if the property is not defined
public MyBean {
}
Some caveats:
If you have many beans that depend on "business" feature in order to avoid placing #ConditionalOnProperty you can do one of the following:
Define your own #Component annotation:
// runtime retention, place on class
#Component
#ConditionalOnProperty(...)
#MyFeatureComponent
... and use it in all the beans that define the feature:
#MyFeatureComponent
public class MyBean
{}
Use Java Configuration instead of annotations:
#Configuration
#ConditionalOnProperty(...)
public class MyFeatureConfiguration {
#Bean
public MyBean myBean(){return new MyBean();}
#Bean
public MyAnotherBean myAnotherBean(){return new MyAnotherBean();}
}
In this case you don't need to place any annotation on MyBean at all.
Spring also has a concept of profiles which is just the same, something that it under the hood implemented with these conditionals.
It allows however to define configuration files per profile, so you might want to read about #Profile annotation as well.
As for the bean definitions - this is way more advanced stuff, in general when spring loads it "recognizes" which bean should be loaded and in which order and for doing that it creates a bean definition before loading the bean. So if you hook into this process you can define your own bean definitions if you want and spring will create beans based on these definitions as well. So basically its a hook that allows altering the bean defitions / create new one during the startup process and hence affect the actual beans that will be loaded into the application context.
I doubt, but if you really need that, read about Bean Factory Post Processors in spring.
There are spring boot 2.0.2 configuration
#Configuration
public class ApiConfig {
#Bean
#Profile("!tests")
#ConditionalOnProperty(name = "enabled", havingValue = "true")
public MyService service() {
return new MyServiceImpl();
}
}
... and some controller which should be created and added to application context only if MyService bean is initialized.
#RestController
#ConditionalOnBean(MyService.class)
public class MyController {
#Autowired
private MyService service;
}
It works Ok. But occasionally spring boot skips MyController creating. According to the logs MyService is created, but after any other beans(including all controllers), at the end.
Why boot does not process #Configuration beans prior to #RestController?
Thanks.
Why boot does not process #Configuration beans prior to #Controller?
Thanks.
Because Spring doesn't guarantee that.
As well as #ConditionalOnBean warns about this kind of issue in this specification :
The condition can only match the bean definitions that have been
processed by the application context so far and, as such, it is
strongly recommended to use this condition on auto-configuration
classes only. If a candidate bean may be created by another
auto-configuration, make sure that the one using this condition runs
after.
And you don't use the annotation in an auto-configuration class. You indeed specified it in a class annotated with #RestController.
I think that to achieve your requirement you should move the #RestController bean declaration in a #Configuration class that's imported via an EnableAutoConfiguration entry in spring.factories.
Have seen below code. Why we need to use this Configuration and Service annotation together.
#Configuration
#Service
public class SomeClass{
#Bean
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public MongoClient somemethod(#Value){
.....
return mongoClient;
}
Also #Bean default scope is singleton then why again mention
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
The #Service annotation makes SomeClass a bean, whereas the #Configuration and #Bean are intended to create bean definitions for classes that you did not write(i.e. library classes).
And indeed the default scope is a singleton so the annotation can be ommited.
#Configuraton and #Service annotations has different purposes.
#Configuration annotation indicates that a class declares one or more bean methods and may be processed by spring container to generate bean definitions and service requests for those beans at runtime.
#Service annotation indicates than an annotated class is a "Business Service Facade" or similar thing.
Singleton is the default scope for a Spring Bean. So it is not necessary to define its scope. However, for better clarity and understanding, you can highlight this fact by using the #Scope annotation.
I and my friend were discussed about #ComponentScan and #Import. Which one is better?
We have 2 different ideas.
#ComponentScan: Easy to use, import all beans from the component
scan.
#Import: You need to know what component you want to use, no need to scan all.
How about your idea? Which one is better for you to use?
Thanks!
#Import is used to import Java configuration classes marked with #Configuration/#Component typically. So if you have a bean inside this component, Spring will load it into Application Context. You can just put the name of the component or class and Spring will pull it up for you.
However, by using #ComponentScan, you tell the application which packages to scan for java classes are annotated with #Configuration/#Component (or any of #Component's sub-annotations like #Service or #Repository etc) and load all of them up in Application Context so they can be autowired when required. If there are inner instances that need to be populated, Spring will take care of it.
You can read more about #Import and #ComponentScan on their respective doc pages.
This page explains pretty well the difference.
#ComponentScan scans and searches for any beans inside packages/classes specified under basePackageClasses or basePackages options, whichever is configured.
This option also allows you to filter some classes that you do not want to be included in search.
#Import is like clubbing one java configuration into another.
eg:
#Configuration
#ComponentScan(basePackages="com.stackoverflow")
public class Dbconfig {
#Bean
public Datasource dSource(){
return new Datasource()
}
}
#Configuration
#Import(Dbconfig.class)
#ComponentScan(basePackages="org.hellospring")
public class AppConfig {
...// beans
}
So here, if we check AppConfig class,
it will include all beans registered in Dbconfig configuration class including inside of package com.stackoverflow
+
It will include all beans inside AppConfig class and beans under package org.hellospring
In the past I have seen people using the following 2 idioms to inject dependencies from the same #Configuration:
#Configuration
public class MyConfiguration {
#Bean
public MyBeanDependencyA myBeanDependencyA(){
return new MyBeanDependencyA();
}
#Bean . //IDIOM 1
public MyBeanDependencyB1 myBeanDependencyB1(){
return new MyBeanDependencyB1(myBeanDependencyA());
}
#Bean //IDIOM 2
public MyBeanDependencyB2 myBeanDependencyB2(MyBeanDependencyA myBeanDependencyA){
return new MyBeanDependencyB1(myBeanDependencyA);
}
}
Is there any practical difference between them?
Does Spring process the whole instantiation method in each call for IDIOM 1? (relevant if method has any side-effect, might be not idempotent)?
Does otherwise Spring inject the global managed instance when injecting for IDIOM 1? (relevant If some external process changes the state of the original singleton bean)
Is Spring container that smart?
Does Spring process the whole instantiation method in each call for IDIOM 1? (relevant if method has any side-effect, might be not idempotent)?
By default #Configuration classes are proxied at runtime so the MyBeanDependencyA will be created once and myBeanDependencyA() will be called only once by Spring and next calls will be proxied to return the same instance (as far as example that you shared is concerned). There will be only one instance of this bean in the context as it's scope is Singleton.
Does otherwise Spring inject the global managed instance when injecting for IDIOM 1? (relevant If some external process changes the state of the original singleton bean)
The IOC container will return same instance of Singleton bean when it is queried to do so. Since it is a Singleton all changes to this bean (if it is mutable) will be visible to components that have reference to it.
As a side note you can disable autoproxing of configuration class since Spring 5.2 by using :
#Configuration(proxyBeanMethods = false)
which will prevent proxying calls of methods annotated with #Bean invoked from other #Bean methods.
Does Spring process the whole instantiation method in each call for IDIOM 1?
No, This is called inter-bean dependencies, a method that annotated with #Bean annotation in #Configuration class will create a bean in spring IOC container
The #Bean annotation is used to indicate that a method instantiates, configures and initializes a new object to be managed by the Spring IoC container. For those familiar with Spring's XML configuration the #Bean annotation plays the same role as the element. You can use #Bean annotated methods with any Spring #Component, however, they are most often used with #Configuration beans.
Does otherwise Spring inject the global managed instance when injecting for IDIOM 1?
Yes, spring injects the same bean if it is required at multiple places Basic concepts: #Bean and #Configuration This inter-bean dependencies will only work in combination of #Bean and #Configuration which also prevents calling same bean method multiple times.
Only using #Bean methods within #Configuration classes is a recommended approach of ensuring that 'full' mode is always used. This will prevent the same #Bean method from accidentally being invoked multiple times and helps to reduce subtle bugs that can be hard to track down when operating in 'lite' mode.