Say I have some Java class named SomeClassConfig in which I want to define a dependency injection like the following;
#Configuration
public class SomeClass {
#Bean
SomeOtherClass someOtherClass() {
FactoryClass factory = UtilFactoryClass.getDefaultFactory();
return factory.create();
}
}
Here UtilFactoryClass denotes some library that allows me to create a factory class, which in turn allows me to create an instance of the object I am interested in. My problem is that the above-mentioned default factory is initialized after some time, so I would like for the bean to be instantiated / injected after the instantiation the default FactoryClass instance. Is this possible? UtilFactoryClass has no knowledge of the Spring Boot framework, and I tried to apply the #DependsOn annotation, but realized it only allows for me to depend on other Beans.
The concrete 'getDefaultFactory' method I am trying to apply is the following: Link. It is associated to a library named Keycloak. My problem is that the factory obtained from this method is null until a certain point in the life cycle of the application.
Do you mean:
#Configuration
public class SomeClass {
#Bean
SomeOtherClass someOtherClass() { //argument injection also possible
return factory().create();
}
#Bean
FactoryClass factory() {
//check/wait for condition e.g.:
while (!UtilityFactory.isInitialized()) {
try {
Thread.sleep(1000);
// better: TimeUnit.XXX.sleep(), and even better use an (spring managed) executor
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
return UtilFactoryClass.getDefaultFactory();
}
}
"Let spring manage the factory"!? ;)
For the check/wait part, see: https://www.baeldung.com/java-delay-code-execution
Related
I am building a library based on Spring Framework and I want to allow users invoke Library's methods in parallel.
In my main class I autowire Service class:
#Autowired
private ExportListCommand exportList;
And that's implementation for Library's method:
public ResponseContainer<ExportListResponse> exportList(ExportListOptions options) {
exportList.setoAuthClient(oAuthClient);
ResponseContainer<ExportListResponse> result = exportList.executeCommand(options);
return result;
}
ExportListCommand is defined as a Bean:
#Bean
#Scope("prototype")
public ExportListCommand exportList() {
return new ExportListCommand();
}
When I as a Library user run 2 exportList's methods in parallel Spring creates only single ExportListCommand bean since it autowired only once. But in reality I need 2 independent ExportListCommand beans. I also tried to change #Scope(value="prototype") to #Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS), but that also does not work as I need: Spring creates ExportListCommand bean for each method invocation and I lose oAuthClient value since I get new object.
I made it work only with AnnotationConfigApplicationContext.getBean() approach which I would like to avoid.
What my options are? Thanks.
I believe you are looking to work with a 'factory' object.
There are two primary ways I would consider this from a Spring standpoint.
The 'Java' way: Create a factory object that will return instances of ExportListCommand
This factory would look something like this:
class ExportListCommandFactory {
ExportListCommand newInstance() {
return new ExportListCommand();
}
}
and would be used in your method like this:
#Autowire
private ExportListCommandFactory commandFactory;
public ResponseContainer<ExportListResponse> exportList(ExportListOptions options) {
final ExportListCommand exportList = commandFactory.newInstance();
exportList.setoAuthClient(oAuthClient);
ResponseContainer<ExportListResponse> result = exportList.executeCommand(options);
return result;
}
Of course, doing this would require that you change your configuration to contain a bean that is an ExportListCommandFactory rather than an ExportListCommand.
Alternatively, you could consider...
The 'Spring' way: Use FactoryBean
The only thing you should need to do here is, in your main class, #Autowire a FactoryBean<ExportListCommand> instead of the ExportListCommand, and in your method where you need to invoke the method, consult the factory to get your instance.
#Autowire
private FactoryBean<ExportListCommand> commandFactory;
public ResponseContainer<ExportListResponse> exportList(ExportListOptions options) {
final ExportListCommand exportList = commandFactory.getObject();
exportList.setoAuthClient(oAuthClient);
ResponseContainer<ExportListResponse> result = exportList.executeCommand(options);
return result;
}
You shouldn't need to change your configuration, as FactoryBean is a special bean that will consult the ApplicationContext/BeanFactory for the instance at each invocation of getObject().
The following example shows explicit wiring of dependencies using spring java config that results in a different bean being wired in while using and interface for a spring configuration class.
This seems like it shouldn't occur or at least give the normal warning that there are two beans as candidates for autowiring and it doesn't know which to select.
Any thoughts on this issue? My guess is there is no real name spacing between configuration classes as is implied by the syntax "this.iConfig.a()" Could this be considered a bug (if only for not warning about the 2 candidate beans)?
public class Main
{
public static void main( final String[] args )
{
final ApplicationContext context = new AnnotationConfigApplicationContext( IConfigImpl.class, ServiceConfig.class );
final Test test = context.getBean( Test.class );
System.out.println( test );
}
}
public class Test
{
private final String string;
public Test( final String param )
{
this.string = param;
}
public String toString()
{
return this.string;
}
}
#Configuration
public interface IConfig
{
#Bean
public String a();
}
#Configuration
public class IConfigImpl implements IConfig
{
#Bean
public String a()
{
return "GOOD String";
}
}
#Configuration
public class ServiceConfig
{
#Autowired
IConfig iConfig;
#Bean
Test test()
{
return new Test( this.iConfig.a() );
}
#Bean
String a()
{
return "BAD String";
}
}
In this case, I would expect to have "GOOD String" to be always be wired in the Test object, but flipping the order of IConfigImpl.class, ServiceConfig.class in the context loader changes which string is loaded.
Tested with Spring 4.0.7
EDIT: Further testing shows this has nothing to to with inherented configs. Same thing results if you drop the IConfig interface.
I believe this was a behavior of Spring for years.
If you redefine a bean, the one that is being loaded as last wins.
Another question would be how to control the order of bean loading when java configs are used. Check out this article http://www.java-allandsundry.com/2013/04/spring-beans-with-same-name-and.html which shows you how to do the ordering by using #Import of the other Spring java config.
The solution is actually simple - if you need to override a previously
defined bean(without say the flexibility of autowiring with a
different bean name), either use the XML bean configuration for both
the bean being overridden and the overriding bean or use the
#Configuration. XML bean configuration is the first example in this
entry, the one with #Configuration would be something like this:
#Configuration
public class Context1JavaConfig {
#Bean
public MemberService memberService() {
return new MemberSvcImpl1();
}
}
#Configuration
#Import(Context1JavaConfig.class)
public class Context2JavaConfig {
#Bean
public MemberService memberService() {
return new MemberSvcImpl2();
}
}
Stepan has mentioned the issue of order. The following is about your comment on their answer
Overriding beans of the same name makes sense, but in this case, I'm
specifically referencing the bean as specified in the iConfig
configuration. I would expect to get the one specified there.
In order to implement #Configuration and the caching of beans so that calls like
#Configuration
class Example {
#Bean
public UncaughtExceptionHandler uncaughtExceptionHandler() {
return (thread, throwable) -> System.out.println(thread + " => " + throwable.getMessage());
}
#Bean
#Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Thread newThread() {
Thread thread = new Thread();
thread.setUncaughtExceptionHandler(uncaughtExceptionHandler()); // <<<<<< allowing this
return thread;
}
}
Spring actually uses CGLIB to create a proxy subtype of the #Configuration annotated class. This proxy maintains a reference to the backing ApplicationContext and uses that to resolve a bean.
So the call in your example
return new Test(this.iConfig.a());
isn't really invoking IConfigImpl#a(). It invokes this code (as of 4.2) from the proxy interceptor. The code uses the corresponding Method to determine the target bean name and uses the ApplicationContext's BeanFactory to resolve the bean. Since the bean definition for a bean named a has already been overriden, that new bean definition gets used. That bean definition is using the ServiceConfig#a() method as its factory method.
This is described in the documentation, here
All #Configuration classes are subclassed at startup-time with CGLIB.
In the subclass, the child method checks the container first for any
cached (scoped) beans before it calls the parent method and creates a
new instance.
Could this be considered a bug [...]?
I don't believe so. The behavior is documented.
I'd like to configure "transactional" beans from my Spring #Configuration class instead of annotating the class implementation itself with #Transactional.
Kind of like the old school way, configuring transactional advice from an XML file, but without needing a String reference to my class/method names to create pointcuts.
The reason is that the bean implementation is in another code base, and the module it belongs to doesn't depend on Spring. Read : I'm not touching the source code of that bean, just instanciating it. The class is final, can't extend it either to add Spring annotations to the child class.
Let's say that all the methods must be transactional, for simplicity.
The bean implementation :
/** This class has no Spring dependency... */
// #Transactional <- which means I can't use this here
public final class ComplexComponentImpl implements ComplexComponent {
private SomeRepository repo;
public ComplexComponentImpl(SomeRepository repository) { this.repo = repository }
public void saveEntities(SomeEntity e1, SomeEntity e2) {
repo.save(e1);
throw new IllegalStateException("Make the transaction fail");
}
What I want to do in my configuration class (and which doesn't work in my unit test) :
#Configuration
#EnableTransactionManagement
public class ComplexComponentConfig {
#Bean
#Transactional // <- Make the bean transactional here
public ComplexComponent complexComponent() {
return new ComplexComponentImpl(repository());
}
// ...
}
The example above doesn't work, indeed, as nothing gets "transactional" at runtime : entity e1 is persisted even though the exception is thrown.
Note that my transaction management setup works works perfectly well with an implementation class marked with #Transactional.
Question : Is is it possible to declare #Beans transactional from a #Configuration class, or is there any alternative taking into accounts the constraints above ?
Found something built-in that is the sum of #Mecon's and #Erik Gillespie's answers, with limited boilerplate.
Spring already provides a TransactionProxyFactoryBean that just sets up a transactional proxy on any object. Much of the setup could be refactored to some utility method :
#Configuration
#EnableTransactionManagement
public class ComplexComponentConfig {
/** NOT A #Bean, this object will be wrapped with a transactional proxy */
public ComplexComponent complexComponentImpl() {
return new ComplexComponentImpl(repository());
}
#Bean
public ComplexComponent complexComponent() {
TransactionProxyFactoryBean proxy = new TransactionProxyFactoryBean();
// Inject transaction manager here
proxy.setTransactionManager(txManager());
// Define wich object instance is to be proxied (your bean)
proxy.setTarget(complexComponentImpl());
// Programmatically setup transaction attributes
Properties transactionAttributes = new Properties();
transactionAttributes.put("*", "PROPAGATION_REQUIRED");
proxy.setTransactionAttributes(transactionAttributes);
// Finish FactoryBean setup
proxy.afterPropertiesSet();
return (ComplexComponent) proxy.getObject;
}
// ...
}
I think you probably can't use #Transactional in that manner. One of spring's in-built PostProcessors, are supposed to scan all classes (beans) that have that annotation, and the create Aspects accordingly.
About alternatives: I would write an Adapter class for each 3rd party class I have to use. And then make those Adapter classes be Spring Beans.
You can't use #Transactional in that way but you can programmatically configure aspects with Spring.
Spring documentation for programmatically defining aspects:
http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-aspectj-programmatic
http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/aop-api.html
The examples in the documentation are very simple. Defining transaction aspects will likely be more complicated and I wouldn't be surprised if you find it easier to just use the convenience of XML-based proxies or take #Mecon's advice and write adapters.
You can use spring's AOP capabilities to add the transaction interceptor to your bean. Just create an Advisor bean that specifies a pointcut and adds a TranscationInterceptor.
#Bean
public ComplexComponent complexComponentImpl() {
return new ComplexComponentImpl(repository());
}
#Bean
public Advisor advisorBean(TransactionManager txManager) {
Class<?> targetClass = ComplexComponent .class;
int propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRED;
return allMethodsTxAdvice(txManager, targetClass, propagationBehavior);
}
/**
* Extracted method for reuse.
*/
private DefaultPointcutAdvisor allMethodsTxAdvice(TransactionManager txManager, Class<?> targetClass, int propagationBehavior) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
String pointcutExpression = MessageFormat.format("execution(* {0}.*(..)))", targetClass.getName());
pointcut.setExpression(pointcutExpression);
MatchAlwaysTransactionAttributeSource tas = new MatchAlwaysTransactionAttributeSource();
TransactionAttribute transactionAttribute = new DefaultTransactionAttribute(propagationBehavior);
tas.setTransactionAttribute(transactionAttribute);
TransactionInterceptor transactionInterceptor = new TransactionInterceptor(txManager, tas);
return new DefaultPointcutAdvisor(pointcut, transactionInterceptor);
}
PS: You don't need to call afterPropertiesSet just return the FactoryBean and spring will handle all lifecycle callbacks. E.g.
#Bean
public FactoryBean<Object> complexComponent(TransactionManager tx) {
TransactionProxyFactoryBean proxyFactory = new TransactionProxyFactoryBean();
proxyFactory.setTransactionManager(tx);
proxyFactory.setTarget(complexComponentImpl());
Properties transactionAttributes = new Properties();
transactionAttributes.put("*", "PROPAGATION_REQUIRED");
proxyFactory.setTransactionAttributes(transactionAttributes);
return proxyFactory;
}
What is the Spring Framework equivalent to FactoryModuleBuilder, #AssistedInject, and #Assisted in Google Guice? In other words, what is the recommended approach using Spring to create factory objects whose methods accept arguments that the application (not the container) must provide?
The Spring static factory method is not the same as FactoryModuleBuilder. FactoryModuleBuilder builds a Guice module that generates "factories" that implement the Factory Method Pattern. Unlike a Spring static factory method, the methods of these factory objects are instance methods, not static methods. The problem with a static factory method is that it is static and doesn't implement an interface so it cannot be replaced with an alternative factory implementation. Different FactoryModuleBuilder instances, however, can build different factories that implement the same interface.
Spring has no equivalent to the Guice FactoryModuleBuilder. The closest equivalent would be a Spring #Configuration class that provides a factory bean that implements a factory interface whose methods accept arbitrary arguments from the application. The Spring container could inject dependencies into the #Configuration object that it, in turn, could supply to the factory constructor. Unlike with FactoryModuleBuilder, the Spring approach produces a lot of boilerplate code typical of factory implementations.
Example:
public class Vehicle {
}
public class Car extends Vehicle {
private final int numberOfPassengers;
public Car(int numberOfPassengers) {
this.numberOfPassengers = numberOfPassengers;
}
}
public interface VehicleFactory {
Vehicle createPassengerVehicle(int numberOfPassengers);
}
#Configuration
public class CarFactoryConfiguration {
#Bean
VehicleFactory carFactory() {
return new VehicleFactory() {
#Override
Vehicle createPassengerVehicle(int numberOfPassengers) {
return new Car(numberOfPassengers);
}
};
}
}
I'm not entirely certain that this question is a dupe, (only 90% sure), but this answer:
https://stackoverflow.com/a/13243066/1768232
Seems to have the information you need. Specifically, you should do this:
I got it working by fetching an instance of the bean used in the constructor-arg out of the context and then populating it with the values that you are working with at run-time. This bean will then be used as the parameter when you get your factory-generated bean.
public class X {
public void callFactoryAndGetNewInstance() {
User user = context.getBean("user");
user.setSomethingUsefull(...);
FileValidator validator = (FileValidator)context.getBean("fileValidator");
...
}
}
I recommend reading the entire answer.
Suppose I've a class Fruit and it's two subclasses - Apple and Grape:
class Fruit {
public void grind() { }
}
class Apple extends Fruit { }
class Grape extends Fruit { }
In spring properties file, I've a property that decides which bean to register at startup. At a time, I'll only have either Apple or Grape instance registered as a bean. The property is:
# This can be either apple or grape
app.fruit = apple
In the Java configuration file, I'm binding a String attribute using #Value with this property, and based on that, I'll create appropriate instance. I'm trying to use factory pattern here. So, I've a FruitFactory like this:
class FruitFactory {
private Map<String, Fruit> map = new HashMap<String, Fruit>();
public FruitFactory() {
map.put("apple", new Apple());
map.put("grape", new Grape());
}
public Fruit getFruit(String fruit) {
return map.get(fruit);
}
}
And here's my spring configuration class:
class SpringConfig {
#Value("${app.fruit}")
private String fruitType;
#Bean
public FruitFactory fruitFactory() {
return new FruitFactory();
}
#Bean
public Fruit getFruit() {
return fruitFactory().getFruit(fruitType);
}
}
So, here're my few questions:
Will the instances stored in the map inside the factory be spring managed bean? Is there any issue with the implementation? I've tried it, and it is working fine, and I'm confused whether the instances are really spring managed.
I was trying to implement it in a better way, so that when a new fruit comes, I don't have to modify my factory. On way is to provide a register() method in factory and let all the Fruit subclasses invoke it. But the issue is when and how the subclasses will be loaded? I'll not be using the classes, not before putting their instances into the map. Can anyone suggest a better way?
Edit:
As suggested in comment and answer, I've tried using #Profile instead of factory pattern. But I'm facing some issues in that. Here's what I've:
#Configuration
#Profile("apple")
class AppleProfile {
#Bean
public Fruit getApple() {
return new Apple();
}
}
#Configuration
#Profile("grape")
class GrapeProfile {
#Bean
public Fruit getGrape() {
return new Grape();
}
}
And in a ServletListener, I've set the active profile:
class MyServletListener implements ServletContextListener {
#Value("${app.fruit}")
private String fruitType;
public void contextInitialized(ServletContextEvent contextEvent) {
// Get Spring Context
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(contextEvent
.getServletContext());
context.getAutowireCapableBeanFactory().autowireBean(this);
ConfigurableEnvironment configEnvironment = (ConfigurableEnvironment) context.getEnvironment();
logger.debug("0;Setting Active Profile: " + cacheRetrievalMode);
configEnvironment.setActiveProfiles(cacheRetrievalMode);
}
}
This is properly setting the active profile, which I can see. The only issue is, the listener is declared before the ContextLoaderListener, and by the time this is executed, the beans are already been created. Is there any alternative?
Will the instances stored in the map inside the factory be spring
managed bean?
Making the FruitFactory a managed bean
#Bean
public FruitFactory fruitFactory() {
return new FruitFactory();
}
doesn't make any of the objects it's referring to managed beans. However, this
#Bean
public Fruit getFruit() {
return fruitFactory().getFruit(fruitType);
}
does make that one returned Fruit a managed bean. #Bean marks a method as a bean definition and bean factory (it creates the bean). The object you return will be managed by Spring's bean life cycle.
Is there any issue with the implementation?
It seems weird that you're creating a FruitFactory bean but also a Fruit from that same FruitFactory. Are you even going to inject the FruitFactory elsewhere in the application?
I was trying to implement it in a better way, so that when a new fruit
comes, I don't have to modify my factory
Seriously, your factory is messing everything up. Spring already does its job, and more! Annotations make your life easier. You can give an identifier to the #Bean. You can qualify the bean with #Qualifier (and then also qualify the injection target with #Qualifier). You can set a #Profile for when and under which conditions the bean should be initialized.
But the issue is when and how the subclasses will be loaded? I'll not
be using the classes, not before putting their instances into the map.
Can anyone suggest a better way?
You can use bean initMethods, which you specify as a #Bean annotation attribute, or a #PostConstruct annotated method to do post-initialization logic. You can use these to register the beans with the factory, which you'll have injected (but that design doesn't sound right to me, you'd have to show us more.)
You should also look into InitializingBean and FactoryBean.
For setting the active profile, one possibility is to do the following. Create an ApplicationContextInitializer which sets the active profile by reading from a .properties file. You won't be able to use #PropertySources here because this isn't a bean.
Something like
public class ProfileContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
PropertySource<Map<String, Object>> source = null;
try {
source = new ResourcePropertySource("spring.properties");
String profile = (String) source.getProperty("active.profile");
System.out.println(profile);
ConfigurableEnvironment env = applicationContext.getEnvironment();
env.setActiveProfiles(profile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
You can register this in your deployment descriptor
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.yourapp.ProfileContextInitializer</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
When the ContextLoaderListener is created, it will pick up and instantiate your class and call its initialize method. This is done before the WebApplicationContext is refreshed.
You should probably just set a VM argument for the active profile and avoid all of this.