Lets say i have two beans:
class MyBean implements BeanInterface(){}
class MyBean2 implements BeanInterface(){}
And if specific property exists, i want to create MyBean, otherwise I want to create MyBean2(). How can i do this?
#Bean
#ConditionalOnProperty(name = "property.validation")
public BeanInterface beanInterface() {
return new MyBean();
}
works if I want to create MyBean if property exists, but how do I create MyBean2 if it doesn't?
#Bean
#ConditionalOnMissingBean(MyBean.class)
public BeanInterface beanInterface() {
return new MyBean2();
}
complains that method with same name exists, and if i understand it correctly, the methods name need to be camelCase name of the bean.
How do i do this?
Thanks
//edit i tried:
#Bean
#ConditionalOnProperty(name = "property.validation")
#Order(1)
public BeanInterface beanInterface() {
return new MyBean();
}
#Bean("beanInterface")
#ConditionalOnMissingBean(MyBean.class)
#Order(2)
public BeanInterface beanInterface() {
return new MyBean2();
}
but it didnt work, second bean is not getting created when property is missing.
You can specify bean name #Bean("beanInterface") then method name can be anything.
You have Java configuration at your hands, so use that to your advantage. Not everything needs annotations to be fixed.
#Bean
public BeanInterface myBean(Environment env) {
String validation = env.getProperty("property.validation", String.class);
return validation != null ? new MyBean(validation) : new MyBean2();
}
The name of the method doesn't matter it can be anything you like.
Spring and Spring boot provide a a following solution: If you need to choose one implementation of the interface at runtime, than you inject all implementations and choose appropriate one at runtime. Assuming that you have an interface DataSource with multiple implementations here is how you inject them all:
#Autowired
private List<DataSource> dataSources;
You can read about this solution here.
This is a standard solution, but I really don't like it as it is waistful to inject all implementations. So, I wrote a feature that is available as part of MgntUtils open-source library. That feature allows you to create a static factory per each interface, and once you add any implementation of that interface declared as a Bean, that implementation will be added automatically at start up into a relevant factory. So, instead of injecting all implementations in your class you at runtime take from the factory needed implementation. I think it is much more elegant solution, and it has been battle-tested and it works well. Here is Javadoc that explains the concept and has a detailed example on how to use it: Lifecycle management. Also here is the article that describes this feature in detail: Non-intrusive access to "Orphaned" Beans in Spring framework. The library is available as Maven artifact at Maven central ad also on Github including javadoc and source code. In the source code there is a working example on how to use this feature
Related
I have some common interface for refactoring logic in my project. It looks about like this:
public interface RefactorAwareEntryPoint {
default boolean doRefactor() {
if (EventLogService.wasEvent(getEventType())) {
return true;
}
boolean result = doRefactorInternal();
if (result) {
EventLogService.registerEvent(eventType);
}
return result;
}
String getEventType();
boolean doRefactorInternal();
}
And than, when I need to write some refactoring - I implement this interface with methods, mark class like #Component, and Spring in loop evaluate each interface implementation and register it in database.
But we have a lot of refactors (every year - 200-300 new). It's hard to disable old implementations manualy, and we have a lot of beans in our spring-context.
Can we do something, for example, use some annotation - which will disable component creation by some condition?
For example:
#Component
#Enabled(YEAR.2020)
public class CustomRefactor implements RefactorAwareEntryPoint {
// Code implementation
}
And this annotation will work like this (a pseudocode):
if (YEAR.2020) {
create bean -> new CustomRefactor()
}
And when it will be YEAR.2021 - we will have no beans from YEAR.2020 in spring-context.
Use the annotation #Profile that makes application configuration and beans available in certain environments.
You can find more at Spring Boot 2.4.0 reference documentation: 3. Profiles
Spring Profiles provide a way to segregate parts of your application configuration and make it be available only in certain environments. Any #Component, #Configuration or #ConfigurationProperties can be marked with #Profile to limit when it is loaded
Consider each year as a separate environment.
#Component
#Profile("2020")
public class CustomRefactor2020 implements RefactorAwareEntryPoint {
// Code implementation
}
#Component
#Profile("2021")
public class CustomRefactor2021 implements RefactorAwareEntryPoint {
// Code implementation
}
In addition to the answers provided by our colleagues, consider the feature of spring called "Stereotype annotations". This is how well-known annotations like #Service are defined in spring.
In general, the fact that you mark your class with #Component annotation allows you to load the class as a spring bean because the annotated class becomes a subject to a process called "component scanning" - a process happens when you start the application context.
Since spring 4 there is a conditional interface that basically makes possible implementing a logic similar to what you refer to as #Enabled(YEAR.2020).
You might use a built-in "#ConditionalOnProperty" to map the 2020 year to property or even implement a custom conditional logic. I'll assume that you've implemented a custom conditional as #ConditionalOnYear
Now, what's interesting (and this is a "stereotype" feature that I've mentioned at the beginning of the post) is that you may create your own "component" annotation with a custom "conditional" logic and use it "as if" its a regular bean:
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#ConditionalOnYear(2020)
#Component
public #interface Year2020OnlyComponent {
#AliasFor(annotation = Component.class)
String value() default "";
}
#Year2020OnlyComponent
public class CustomRefactor implements RefactorAwareEntryPoint {
// Code implementation
}
You can also improve that by clever usage of #AliasFor annotation to be something like:
#SinceYearComponent(2020)
public class CustomRefactor implements RefactorAwareEntryPoint {
// Code implementation
}
But this is kind of out of scope for this question - so I just mention a direction here.
Of course, it's possible to merely use two annotations as you've suggested even without this "Stereotype" annotation feature:
#Component
#SinceYear(2020) // a custom conditional
public class CustomRefactor implements RefactorAwareEntryPoint {
// Code implementation
}
Check out the BeanFactoryPostprocessor interface. Probably you can remove a bean before it‘s creation.
Else you might implement your own BeanFactory and create the ApplicationContext with your implementation.
You can use excludeFilter annotations provided by spring boot .
As mentioned by others you can always use #Profile annotation to
enable/disable profiles.
Another option is excludeFilter
I know that there are questions similar to this one, but none of them have helped me. I'm following along this tutorial, and the part I can't wrap my mind around is:
#SpringBootApplication
public class Application {
private static final Logger log =
LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
#Bean
public CommandLineRunner demo(CustomerRepository repository) {
return (args) -> {
// save a couple of customers
...
// more lines, etc...
What I don't understand is where the repository passed into demo comes from. I know that the Autowired annotation can do something like that, but it isn't used at all here.
The more specific reason I ask is because I'm trying to adapt what they do here to an application I'm working on. I have a class, separate from all of the persistence/repository stuff, and I want to call repository methods like save and findAll. The issue is that the repository is an interface, so I can't instantiate an object of it to call the methods. So do I have to make a new class that implements the interface and create an object of that? Or is there an easier way using annotations?
When creating a #Bean, adding the repository in the parameters of the bean is enough to wire the repos in your bean. This works pretty much like adding #Autowired annotation inside a class that is annotated as #Component or something similar.
Spring works mostly with interface, since that is simplier to wire vs wiring concrete classes.
Can you try #Repository before the declaration of class? Worked for me in a Spring MVC structure.
#Repository
public class EntityDAOImpl implements EntityDAO{
...
}
The thing to wrap your head around is a Spring Boot application at startup time aims to resolve its dependancy tree. This means discovering and instantiating Beans that the application defines, and those are classes annotated with #Service, #Repository, etc.
This means the default constructor (or the one marked with #Autowire) of all beans is invoked, and after all beans have been constructed the application starts to run.
Where the #Bean annotation comes into play is if you have a bean which does not know the values of it's constructor parameters at compile time (e.g. if you want to wire in a "started at" timestamp): then you would define a class with an #Configuration annotation on it, and expose an #Bean method in it, which would return your bean and have parameters that are the beans dependencies. In it you would invoke the beans constructor and return the bean.
Now, if you want a certain method of some class to be invoked after the application is resolved, you can implement the CommandLineRunner interface, or you can annotate a method with #PostConstruct.
Some useful links / references:
https://docs.spring.io/spring-javaconfig/docs/1.0.0.m3/reference/html/creating-bean-definitions.html
https://www.baeldung.com/spring-inject-prototype-bean-into-singleton
Running code after Spring Boot starts
Execute method on startup in Spring
In my ApplicationContext I have several Beans being created the same style. So I have a lot of dublicated code writing a FactoryBean for each of this beans. Those beans have a common ground, implementing all one special interface.
I would like to move all that bean creation to one factory. That one would have to provide a methode like this
<T extends CommonInterface> T createInstance(Class<T> clazz);
There I could implement all the instantiation necessary to create one of my special beans.
My implementation would be called by spring for
#Autowired
private MyCommonInterfaceImplementation impl;
in that way
createInstance(MyCommonInterfaceImplementation.class)
So far I looked at BeanFactory and FactoryBean, both seem not to be I'm searching for.
Any suggestions?
why not use #bean
#Bean
public MyCommonInterfaceImplementation getMyCommonInterfaceImplementation(){
return MyBeanFactory.createInstance(MyCommonInterfaceImplementation.class);
}
//should autowire here
#Autowired
private MyCommonInterfaceImplementation impl;
Basically you need the #Bean annotation on a "factory" only if you need some special handling during the creation of a bean.
If everything can be #Autowired, either by setters, fields, or one constructor, and nothing else needs to be done on a bean during initialization, you can simply declare the annotation #Component on each implementation of your interface. This works as long as you have component scanning active inside your application. The result will be that for each component spring will create a bean which you can use.
I'm writing this on a mobile so showing code is not the best. Just follow some tutorial on #ComponentScan, or if you need, let me know and I can augment this answer with an example.
As of Spring 4.3 you no longer have to annotate your bean classes and you can let them be instantiated via a componentscan.
#Configuration
#ComponentScan(
value = "some.package.path",
includeFilters = {
#Filter(type = ASSIGNABLE_TYPE, value = {
MyClass1.class,
MyClass2.class,
MyClass3.class
})
})
This actually creates beans for the three classes listed there. The example should work without filters as well (everything in the package becomes a bean). This works as long as the classes have a single constructor that can be used for autowiring. I don't think it is possible to filter for all implementations of a particular interface and then register a bean.
To do that, you might do something with a ContextListener and e.g. use reflection to find out what classes to instantiate and then use context.autowire(..) to inject any dependencies from your context. A bit hacky but it might work.
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
MyClass bean
= context
.getAutowireCapableBeanFactory()
.autowire(MyClass.class, Autowire.BY_NAME.value(), true);
...
}
That still leaves the problem of how to get the bean registered in the context of course.
You might also be able to adapt the answer to this SO question on how to add beans programmatically.
Finally the best approach I've found is using a ConfigurationClassPostProcessor. As example I've used https://github.com/rinoto/spring-auto-mock
But, since it is quite complicated and "too much magic" to create beans from nothing, we decided to explicitly create those beans via #Bean.
Thanks for your answers.
I got Object coming in a REST web service controller's web method which is locally initialized.
#RequestMapping(method = RequestMethod.POST,value = "/test",headers="Accept=*/*")
public #ResponseBody ModelAndView computeDetails(#RequestBody RequestObj reqObj, ModelMap model) {
System.out.println(reqObj.getcode());
return new ModelAndView("responsedetails", "object", reqObj);
}
This RequestObj object holds the key code to instantiate dependency using factory.
Different codes classes have been defined which implement BaseCode Interface.
How can I use factory method to instantiate particular code class based on code value coming in as BaseCode type in my service bean?
Any idea? Thanks in advance.
What I usually do in such cases is:
inject the factory into the controller using Spring's bean
create a method getBaseCode(String code) in the factory (please note: String here stands for code type, so use the actual code type if not String
make getBaseCode returning the BaseCode interface while constructing the real implementation
supposing you have an execute method in BaseCode, use the getBaseCode method into the controller to get the real collaborator and then call the execute method to perform the actual action
Ignoring the first point (which I think you can easily looking at any Spring tutorial) the factory will be something like
public class BaseCodeFactory {
public BaseCode getBaseCode(String code) {
if(code.equals("something")) return new ThisBaseCodeImpl();
else //and so on
}
}
while computeDetails becomes similar to:
#RequestMapping(method = RequestMethod.POST,value = "/test",headers="Accept=*/*")
public #ResponseBody ModelAndView computeDetails(#RequestBody RequestObj reqObj, ModelMap model) {
//...
factory.getBaseCode(reqObj.getcode()).execute();
//...
}
As a side note, I will not go for names like the one I choose here, I suggest you to look for something more significative in your domain (BaseCode has no meaning for example), take this snippets just as a directive.
Base on OP comment. If you have ThisBaseCodeImpl which makes use of other Spring bean you can
annotate it with #Configurable so, when you use new ThisBaseCodeImpl(/*args if you like*/) its bean are instantiated by Spring. I don't personally like this solution since, in my opinion, it pollutes the code with hidden Spring's bean. On the other hand is quite flexible, since it allows you to manage both runtime constructor arguments and Spring beans
add ThisBaseCodeImpl to the Spring context and change the factory, so that a collaborator for ThisBaseCodeImpl is injected into it.
1st point example:
#Configurable
public class ThisBaseCodeImpl {
#Resource
private Bean bean;
}
2nd point example:
public class BaseCodeFactory {
#Resource
ThisBaseCodeImpl thisBaseCodeImpl;
public BaseCode getBaseCode(String code) {
if(code.equals("something")) return thisBaseCodeImpl;
else //and so on
}
}
I'm not sure if I understood your problem well, but in general spring dependencies have nothing to do here. Just write custom Factory class and return BaseCode implemetation depending on the reqObj.getcode().
I did it this way -
Make your factory as ServletContextAware in a way to get the currentContext. And define getInstance method as
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
ctx.getBean(classNameToBeInstantiated);
Define your bean's inheritance in spring context so that Spring injects its dependencies.
My goal is a framework where concrete types of beans can be easily changed by a properties file. I also prefer annotations to XML. Ideally I'd to use a combination of #Resource and SpEL like this:
#Resource(type="#{myProperties['enabled.subtype']}")
SomeInterface foo;
where I've loaded myProperties with a PropertiesFactoryBean or <util:properties> from a file that includes:
enabled.type = com.mycompany.SomeClassA; // which implements SomeInterface
This doesn't work because the argument of type must be a literal, i.e., no SpEL allowed. What's the best practice here?
Update: See my answer below.
This is exactly the use case for Spring Java Configuration.
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java
Or you can alternatively make a Factory.
Using: org.springframework.beans.factory.FactoryBean<SomeInterface>
The name of the bean that implements FactoryBean will be seen as a "SomeInterface" even though its not.
I think it is not possible, the solution I tend to adopt is to use a factory that creates the different objects depending on a configuration property (enabled.type in your example).
A second alternative could be to use injection by name:
#Resource(name="beanName")
And last, if you use Spring 3.1+ you can try to use profiles, and have different bean sets in different profiles, if that solves your problem.
Spring's Java Configuration and Bean Definition Profiles turn out to be exactly what I was looking for (thanks #Adam-Gent and #Guido-Garcia). The former seems necessary for the dynamic element, and the latter promotes a better practice.
Here's a solution with Java config and properties:
#Configuration
public class SomeClassConfig {
#Value("#{myProperties['enabled.subtype']}")
public Class enabledClass;
#Bean SomeInterface someBean()
throws InstantiationException, IllegalAccessException {
return (SomeInterface) enabledClass.newInstance();
}
}
Here's a slightly less dynamic solution with profiles.
#Configuration
#Profile("dev")
public class DevelopmentConfig {
#Bean SomeInterface someBean() {
return new DevSubtype();
}
}
#Configuration
#Profile("prod")
public class ProductionConfig {
#Bean SomeInterface someBean() {
return new ProdSubtype();
}
}
With profiles, the active profile(s) are declared using one of a variety of methods such as via system property, JVM property, web.xml, etc. For example, with a JVM property:
-Dspring.profiles.active="dev"