How to silently cancel bean creation? - java

#Component
public class MyBean {
#Autowired
public MyBean(#Value("${optional:#{null}}") String optional) {
if (optional == null) {
// cancel bean creation?
}
}
}
How to silently cancel bean creation? I could throw a RuntimeException, but I don't want this cancellation to be considered as an error: the bean must just not be created, the application initialization must go on.

Here you can make use of #Conditional
Step 1- Implement Condition.matches so as to specify when should the bean be created or not.
public class SomeCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return System.getProperty("optional") != null;
}
}
The condition class is referred as direct class (not as spring bean) so it can't use the #Value property injection. See here for alternative
Step 2 - In the configuration class specify the above class as condition to decide the bean creation
#Configuration
public class SomeAppConfig {
#Bean
#Condition(SomeCondition.class)
public MyBean myBean() {
return new MyBean();
}
}
P.S.: I have assumed that you use Java config.

It's not possible.
If you don't create a bean you can't use it. It's just a simple Java class and the property used/autowired in the bean are just useless.
However, you may configure profile base configuration beans for different kind of environments like 'Dev', 'Test' or 'Production'.
https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/

Related

Java Spring configuration when to define bean and when new

I have a configuration class and I was wondering should I define bean to each class or create new.
#Configuration
public class BookConfig {
#Bean
public Read readBook() {
return new ReadBook(new Operation(), new Library(new Location()));
}
}
OR
#Configuration
public class BookConfig {
#Bean
public Operation operation() {
return new Operation();
}
#Bean
public Location location() {
return new Location();
}
#Bean
public Library library() {
return new Library(location());
}
#Bean
public Read readBook() {
return new ReadBook(operation(), library());
}
}
What is the correct way?
If you do not intend to use Operation and Location bean any time then you can skip creation of that bean and use new as in the first option.
But if you think that Operation and Location beans would be used later second approach is better. Though I would suggest a slight modification. You do not have to call the methods instead pass the bean itself as method param.
#Configuration
public class BookConfig {
#Bean
public Operation operation() {
return new Operation();
}
#Bean
public Location location() {
return new Location();
}
#Bean
public Library library(Location location) {
return new Library(location);
}
#Bean
public Read readBook(Location location, Library library) {
return new ReadBook(location, library);
}
}
As a rule of thumb, always remember that anything that is made into a Bean will be managed by the Spring boot context itself. Anything that you declare yourself as "new" will not be managed by spring boot and will be treated as a plain java object.
Beans will be singleton by default and have all the life cycle methods run on them (among other things). During Spring boot context creation at startup, bean dependencies will be resolved and you'll have to design your classes in such a way that there is no circular dependency issue.
If you do a "new" then the scope of those object will be restricted to that particular instance of the class and will be destroyed with the instance once it is garbage collected.

Class based on factory class not available for autowiring

I'm trying to learn the basics of Spring and have defined this class?
public class Processor {
public Processor() {
this.setup();
}
private void setup(){
//run some setup code
}
public String processString(String str) {
// process the string
return str;
}
}
I want to Spring enable this class so I use a factory bean:
Reading https://www.baeldung.com/spring-factorybean I use:
public class Processor implements FactoryBean<Processor> {
#Override
public Processor getObject() throws Exception {
return new Processor();
}
#Override
public Class<?> getObjectType() {
return Processor.class;
}
}
To Test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ProcessorFactory.class)
public class ProcessorTest {
#Autowired
private Processor processor;
#Test
public void testProcessor() {
//Some tests
}
}
This works as expected.
When I try to use
#Autowired
private Processor processor;
elsewhere in my project I receive compile-time error :
Could not autowire. No beans of 'Processor' type found.
Have I not setup the factory correctly? I should annotate the Processor object to indicate it is to be autowired ? Perhaps this is not a valid use case for Factory ?
In general, factory beans are pretty outdated, first spring versions indeed used this approach, but spring has evolved since that time.
The Factory bean itself should be registered in the spring configuration (the very first versions of spring used xml based configuration because Java Annotation did not exist at that time) so the tutorial contains the XML configuration example. Anyway, that's probably the reason of failure. In the test you should also specify the path to the xml configuration otherwise the factory bean won't be loaded.
You can use these factory beans (they're still supported) but they have the following downsides:
They couple your code to the spring framework
A lot of boilerplate (usually in typical application there can be hundreds of beans, so creating a Factory Bean for each one is an overkill).
So you can:
Instead of using Factory Beans, annotate the Processor with #Component annotation (or more specialized #Service).
Alternatively Use Java configuration:
#Configration
public class MyConfig {
#Bean
public Processor processor() {
// optionally slightly customize the creation of the class if required;
return new Processor();
}
}

How to properly overload Spring bean configuration

I'm having two spring(4.2) java configurations, one in a base module and one in a client specific module:
#Configuration
public class BaseConfig {
#Bean
public A getA() {
return new A("aaa");
}
}
#Configuration
public class ClientConfig {
#Bean
public A getA() {
return new A("bbbb");
}
}
During the app load there is always BaseConfig.getA() called, how can I ovverride the base bean factory configuration to have some client specific stuff?
Personally I would NEVER override a bean in spring! I have seen people spend too much time debugging issues related to this. For the same reason I would never use #Primary.
In this case I would have 3 contexts
Context that contains beans unique to the parent context
Context that contains beans unique to the child context
Abstract context that contains all shared beans.
This way you will specify the 2 contexts to load. This could be done programatically, or using profiles. Potentially you will need more contexts, because you probably want some of your beans to be different in tests.
I think that you should take a look at the #Profile annotation. You could simply split configuration into different base and client specific one like:
#Configuration
#Profile("base")
public class BaseConfig {
#Bean
public A getA() {
return new A("aaa");
}
}
#Configuration
#Profile("client")
public class ClientConfig {
#Bean
public A getA() {
return new A("bbbb");
}
}
now run the specific profile by adding
#ActiveProfiles("base") on application main method
spring.profiles.active=base entry in application.properties
or even pass profile name into jvm params
I'm not sure on how to extend bean config classes. One solution is to mark the bean in ClientConfig with #Primary annotation. This will cause the ClientConfig definition of bean A to be used.
If you include both configurations you can check Primary annotation: Primary
Indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If exactly one 'primary' bean exists among the candidates, it will be the autowired value.
#Profile Annotation can be used for this...
#Configuration
#Profile("base")
public class BaseConfig {
#Bean
public A getA() {
return new A("aaa");
}
}
#Configuration
#Profile("client")
public class ClientConfig {
#Bean
public A getA() {
return new A("bbbb");
}
}
Use the following link
https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/
This is an answer to a comment above, but since comments have limited formating and size, I will reply with an answer instead.
how does spring define the ordering and overriding of beans when loading configuration files
It depends what you mean by loading multiple configuration. If you have one spring context and have two classes with #Configuration and do a component scan, then Spring will build the dependency tree, and which ever context (bean) is loaded last will define the bean (as it overrides the fist definition).
If you have have multiple Spring contexts in a parent child relation, then the child and see parent beans, and will also 'override' parent beans if you use child.getBean(type.class). The parent can't see bean from children.
Using #Primary. If you have a Spring context (can come from multiple configurations) that defines two beans of the same type, you will not be able to use context.getBean(type.class) or #AutoWired (without #Qualifier) because you have multiple beans of the same type. This behaviour can be altered if one of the beans is #Primary. I try to avoid the use of #Primary in my own code, but I can see it is used heavily used in Spring boots auto configure system, so I think it has some subtle usage when it comes to framework design.
Here is a small example, note that if you load configuration classes directly, they don't need to have the #Configuration annotation.
public class ParentChildContext {
public static void main(String[] args) {
parentChildContext();
twoConfigurationsSameContext();
}
private static void twoConfigurationsSameContext() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(Parent.class, Child.class);
// if you have two beans of the same type in a context they can be loaded by name
Object childA = ctx.getBean("childA");
System.out.println("childA = " + childA);
Object parentA = ctx.getBean("parentA");
System.out.println("parentA = " + parentA);
// since both configurations define A, you can't do this
ctx.getBean(A.class);
}
private static void parentChildContext() {
ApplicationContext parentCtx = new AnnotationConfigApplicationContext(Parent.class);
A parentA = parentCtx.getBean(A.class);
System.out.println("parent = " + parentA);
AnnotationConfigApplicationContext childCtx = new AnnotationConfigApplicationContext();
childCtx.register(Child.class);
childCtx.setParent(parentCtx);
childCtx.refresh();
A childA = childCtx.getBean(A.class);
System.out.println("child = " + childA);
}
public static class Parent {
#Bean
//#Primary // if you enable #Primary parent bean will override child unless the context is hierarchical
public A parentA() {
return new A("parent");
}
}
public static class Child {
#Bean
public A childA() {
return new A("child");
}
}
public static class A {
private final String s;
public A(String s) {
this.s = s;
}
#Override
public String toString() {
return "A{s='" + s + "'}";
}
}
}

Inject spring bean dynamically

In a java-spring web-app I would like to be able to dynamically inject beans.
For example I have an interface with 2 different implementations:
In my app I'm using some properties file to configure injections:
#Determines the interface type the app uses. Possible values: implA, implB
myinterface.type=implA
My injections actually loaded conditionally relaying on the properties values in the properties file. For example in this case myinterface.type=implA wherever I inject MyInterface the implementation that will be injected will be ImplA (I accomplished that by extending the Conditional annotation).
I would like that during runtime - once the properties are changed the following will happen (without server restart):
The right implementation will be injected. For example when setting myinterface.type=implB ImplB will be injected where-ever MyInterface is used
Spring Environment should be refreshed with the new values and re-injected as well to beans.
I thought of refreshing my context but that creates problems.
I thought maybe to use setters for injection and re-use those setters once properties are re-configured. Is there a working practice for such a requirement?
Any ideas?
UPDATE
As some suggested I can use a factory/registry that holds both implementations (ImplA and ImplB) and returns the right one by querying the relevant property.
If I do that I still have the second challenge - the environment. for example if my registry looks like this:
#Service
public class MyRegistry {
private String configurationValue;
private final MyInterface implA;
private final MyInterface implB;
#Inject
public MyRegistry(Environmant env, MyInterface implA, MyInterface ImplB) {
this.implA = implA;
this.implB = implB;
this.configurationValue = env.getProperty("myinterface.type");
}
public MyInterface getMyInterface() {
switch(configurationValue) {
case "implA":
return implA;
case "implB":
return implB;
}
}
}
Once property has changed I should re-inject my environment. any suggestions for that?
I know I can query that env inside the method instead of constructor but this is a performance reduction and also I would like to think of an ider for re-injecting environment (again, maybe using a setter injection?).
I would keep this task as simple as possible. Instead of conditionally load one implementation of the MyInterface interface at startup and then fire an event that triggers dynamic loading of another implementation of the same interface, I would tackle this problem in a different way, that is much simpler to implement and maintain.
First of all, I'd just load all possible implementations:
#Component
public class MyInterfaceImplementationsHolder {
#Autowired
private Map<String, MyInterface> implementations;
public MyInterface get(String impl) {
return this.implementations.get(impl);
}
}
This bean is just a holder for all implementations of the MyInterface interface. Nothing magic here, just common Spring autowiring behavior.
Now, wherever you need to inject a specific implementation of MyInterface, you could do it with the help of an interface:
public interface MyInterfaceReloader {
void changeImplementation(MyInterface impl);
}
Then, for every class that needs to be notified of a change of the implementation, just make it implement the MyInterfaceReloader interface. For instance:
#Component
public class SomeBean implements MyInterfaceReloader {
// Do not autowire
private MyInterface myInterface;
#Override
public void changeImplementation(MyInterface impl) {
this.myInterface = impl;
}
}
Finally, you need a bean that actually changes the implementation in every bean that has MyInterface as an attribute:
#Component
public class MyInterfaceImplementationUpdater {
#Autowired
private Map<String, MyInterfaceReloader> reloaders;
#Autowired
private MyInterfaceImplementationsHolder holder;
public void updateImplementations(String implBeanName) {
this.reloaders.forEach((k, v) ->
v.changeImplementation(this.holder.get(implBeanName)));
}
}
This simply autowires all beans that implement the MyInterfaceReloader interface and updates each one of them with the new implementation, which is retrieved from the holder and passed as an argument. Again, common Spring autowiring rules.
Whenever you want the implementation to be changed, you should just invoke the updateImplementations method with the name of the bean of the new implementation, which is the lower camel case simple name of the class, i.e. myImplA or myImplB for classes MyImplA and MyImplB.
You should also invoke this method at startup, so that an initial implementation is set on every bean that implements the MyInterfaceReloader interface.
I solved a similar issue by using org.apache.commons.configuration.PropertiesConfiguration and org.springframework.beans.factory.config.ServiceLocatorFactoryBean:
Let VehicleRepairService be an interface:
public interface VehicleRepairService {
void repair();
}
and CarRepairService and TruckRepairService two classes that implements it:
public class CarRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a car");
}
}
public class TruckRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a truck");
}
}
I create an interface for a service factory:
public interface VehicleRepairServiceFactory {
VehicleRepairService getRepairService(String serviceType);
}
Let use Config as configuration class:
#Configuration()
#ComponentScan(basePackages = "config.test")
public class Config {
#Bean
public PropertiesConfiguration configuration(){
try {
PropertiesConfiguration configuration = new PropertiesConfiguration("example.properties");
configuration
.setReloadingStrategy(new FileChangedReloadingStrategy());
return configuration;
} catch (ConfigurationException e) {
throw new IllegalStateException(e);
}
}
#Bean
public ServiceLocatorFactoryBean serviceLocatorFactoryBean() {
ServiceLocatorFactoryBean serviceLocatorFactoryBean = new ServiceLocatorFactoryBean();
serviceLocatorFactoryBean
.setServiceLocatorInterface(VehicleRepairServiceFactory.class);
return serviceLocatorFactoryBean;
}
#Bean
public CarRepairService carRepairService() {
return new CarRepairService();
}
#Bean
public TruckRepairService truckRepairService() {
return new TruckRepairService();
}
#Bean
public SomeService someService(){
return new SomeService();
}
}
By using FileChangedReloadingStrategy your configuration be reload when you change the property file.
service=truckRepairService
#service=carRepairService
Having the configuration and the factory in your service, let you can get the appropriate service from the factory using the current value of the property.
#Service
public class SomeService {
#Autowired
private VehicleRepairServiceFactory factory;
#Autowired
private PropertiesConfiguration configuration;
public void doSomething() {
String service = configuration.getString("service");
VehicleRepairService vehicleRepairService = factory.getRepairService(service);
vehicleRepairService.repair();
}
}
Hope it helps.
If I understand you correctly then the goal is not to replace injected object instances but to use different implementations during interface method call depends on some condition at run time.
If it is so then you can try to look at the Sring TargetSource mechanism in combination with ProxyFactoryBean. The point is that proxy objects will be injected to beans that uses your interface, and all the interface method calls will be sent to TargetSource target.
Let's call this "Polymorphic Proxy".
Have a look at example below:
ConditionalTargetSource.java
#Component
public class ConditionalTargetSource implements TargetSource {
#Autowired
private MyRegistry registry;
#Override
public Class<?> getTargetClass() {
return MyInterface.class;
}
#Override
public boolean isStatic() {
return false;
}
#Override
public Object getTarget() throws Exception {
return registry.getMyInterface();
}
#Override
public void releaseTarget(Object target) throws Exception {
//Do some staff here if you want to release something related to interface instances that was created with MyRegistry.
}
}
applicationContext.xml
<bean id="myInterfaceFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="MyInterface"/>
<property name="targetSource" ref="conditionalTargetSource"/>
</bean>
<bean name="conditionalTargetSource" class="ConditionalTargetSource"/>
SomeService.java
#Service
public class SomeService {
#Autowired
private MyInterface myInterfaceBean;
public void foo(){
//Here we have `myInterfaceBean` proxy that will do `conditionalTargetSource.getTarget().bar()`
myInterfaceBean.bar();
}
}
Also if you want to have both MyInterface implementations to be Spring beans, and the Spring context could not contains both instances at the same time then you can try to use ServiceLocatorFactoryBean with prototype target beans scope and Conditional annotation on target implementation classes. This approach can be used instead of MyRegistry.
P.S.
Probably Application Context refresh operation also can do what you want but it can cause other problems such as performance overheads.
This may be a duplicate question or at least very similar, anyway I answered this sort of question here: Spring bean partial autowire prototype constructor
Pretty much when you want a different beans for a dependency at run-time you need to use a prototype scope. Then you can use a configuration to return different implementations of the prototype bean. You will need to handle the logic on which implementation to return yourself, (they could even be returning 2 different singleton beans it doesn't matter) But say you want new beans, and the logic for returning the implementation is in a bean called SomeBeanWithLogic.isSomeBooleanExpression(), then you can make a configuration:
#Configuration
public class SpringConfiguration
{
#Bean
#Autowired
#Scope("prototype")
public MyInterface createBean(SomeBeanWithLogic someBeanWithLogic )
{
if (someBeanWithLogic .isSomeBooleanExpression())
{
return new ImplA(); // I could be a singleton bean
}
else
{
return new ImplB(); // I could also be a singleton bean
}
}
}
There should never be a need to reload the context. If for instance, you want the implementation of a bean to change at run-time, use the above. If you really need to reload your application, because this bean was used in constructors of a singleton bean or something weird, then you need to re-think your design, and if these beans are really singleton beans. You shouldn't be reloading the context to re-create singleton beans to achieve different run-time behavior, that is not needed.
Edit The first part of this answer answered the question about dynamically injecting beans. As asked, but I think the question is more of one: 'how can I change the implementation of a singleton bean at run-time'. This could be done with a proxy design pattern.
interface MyInterface
{
public String doStuff();
}
#Component
public class Bean implements MyInterface
{
boolean todo = false; // change me as needed
// autowire implementations or create instances within this class as needed
#Qualifier("implA")
#Autowired
MyInterface implA;
#Qualifier("implB")
#Autowired
MyInterface implB;
public String doStuff()
{
if (todo)
{
return implA.doStuff();
}
else
{
return implB.doStuff();
}
}
}
You can use #Resource annotation for injection as originally answered here
e.g.
#Component("implA")
public class ImplA implements MyInterface {
...
}
#Component("implB")
public class ImplB implements MyInterface {
...
}
#Component
public class DependentClass {
#Resource(name = "\${myinterface.type}")
private MyInterface impl;
}
and then set the implementation type in properties file as -
myinterface.type=implA
Be aware that - if interesting to know about - FileChangedReloadingStrategy makes your project highly dependent on the deployment conditions: the WAR/EAR should be exploded by container and your should have direct access to the file system, conditions that are not always met in all situations and environments.
You can use Spring #Conditional on a property value. Give both Beans the same name and it should work as only one Instance will be created.
Have a look here on how to use #Conditional on Services and Components:
http://blog.codeleak.pl/2015/11/how-to-register-components-using.html
public abstract class SystemService {
}
public class FooSystemService extends FileSystemService {
}
public class GoSystemService extends FileSystemService {
}
#Configuration
public class SystemServiceConf {
#Bean
#Conditional(SystemServiceCondition.class)
public SystemService systemService(#Value("${value.key}") value) {
switch (value) {
case A:
return new FooSystemService();
case B:
return new GoSystemService();
default:
throw new RuntimeException("unknown value ");
}
}
}
public class SystemServiceCondition implements Condition {
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return true;
}
}

Best way to override beans in Spring

I have an application that consists of 2 modules.
First of them is main one and it can work without second module installed.
I have beans with default implementation defined in beans.xml file of main module. And when installing second module I want to keep the ids of those beans but change the implementation to use new classes.
What is the best way to do that?
beans.xml of first module:
...
<bean id="myCoolService" class="com.blabla.defaultCoolServiceImpl">
...
and after the installation of second module I want to use the implementation of myCoolService that is defined in second module.
Upd:
Spring version is 3.2.4.
I need to make as little changes as possible so I need to continue using xml-driven configuration.
One way of doing this is introducing a common interface (I guess one should already be present):
public interface MyInterface {
//...
}
And then in the main module annotate the default implementation with #Service
#Service
public class DefaultImplementation implements MyInterface {
//...
}
Then, if one of your modules needs to override this implementation, use the #Primary-annotation:
#Service
#Primary
public class OverridingImplementation implements MyInterface {
//...
}
Then, the following code:
#Inject
private MyInterface myInterface;
will inject DefaultImplementation if OverridingImplementation is not scanned, and inject OverridingImplementation (without complaining about multiple beans) if it is scanned.
One way to achieve this is going through a proxy, that redirects to the proper implementation. The proxy would normally redirect to the default. It will redirect to module 2 if it is available.
To help the proxy figure out what is available, you may need to have
a member that always points to the default implementation using "name" property.
have a method to register a different bean as the alternate implementation.
For example
Inside MyProxy:
#Autowired
public void setDefaultWorker(Worker defaultWorker) {
this.defaultWorker = defaultWorker;
}
private Worker defaultWorker;
private Worker alternateWorker;
public void registerAlternateWorker(Worker alternateWorker) {
this.alternateWorker = alternateWorker;
}
//To use the worker
private Worker getWorker() {
return alternateWorker == null? defaultWorker : alternateWorker;
}
In Module 1, your default implementation bean should be declared as having the defaultWorker as name
<bean id="defaultWorker" class="MyDefaultWorkerImpl"/>
Module 2 can register itself to the proxy registry on startup using SmartLifeCycle.
if possible,use :
<bean id="myCoolService" class="${IMPL_CLASS_NAME}"/>
Define impl class in a property file.
IMPL_CLASS_NAME=com.blabla.SecondMduleCoolServiceImpl
OR other approach could be :
Lets say your defaultCoolServiceImpl and SecondMduleCoolServiceImpl implement ICoolService interface
You define these bean and an implementation of FactoryBean as below :
<bean id="mydefaultServiceimpl" class="com.blabla.defaultCoolServiceImpl">
<bean id="secondModuleCoolserviceimpl" class="com.blabla.SecondMduleCoolServiceImpl">
<bean id="myCoolService" class="com.blabla.ImplSelector"/>
public class ImplSelector implements FactoryBean<ICoolService>, ApplicationContextAware {
private ApplicationContext iApplicationContext;
// #Value("#{corePropertyConfigurer['defaultOrCool']}") you can injcet via property file.
private String defaultOrCool = "cool" ;
#Override
public ICoolService getObject() throws Exception {
if (StringUtils.equals(defaultOrCool, "default")) {
return iApplicationContext.getBean("mydefaultServiceimpl", ICoolService.class);
}
return iApplicationContext.getBean("secondModuleCoolserviceimpl", ICoolService.class);
}
#Override
public Class<?> getObjectType() {
return ICoolService.class;
}
#Override
public boolean isSingleton() {
return true;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
iApplicationContext = applicationContext;
}
}
Then you can access myCoolService via autowiring or applicationContext.getBean("myCoolService", ICoolService.class);

Categories