I'm using Axon 4.3 with JPA/Spring.
I want to inject entityManager in my interceptor, so i used ContainerManagedEntityManagerProvider in my configuration. but i have this error when i run my application
Description: Parameter 0 of method configureCommandBus in AxonConfig
required a bean of type
'org.axonframework.springboot.util.jpa.ContainerManagedEntityManagerProvider'
that could not be found.
Action: Consider defining a bean of type
'org.axonframework.springboot.util.jpa.ContainerManagedEntityManagerProvider'
in your configuration.
#Configuration
#AutoConfigureAfter(AxonAutoConfiguration.class)
public class AxonConfig {
#Bean
public CommandBus configureCommandBus(org.axonframework.springboot.util.jpa.ContainerManagedEntityManagerProvider containerManagedEntityManagerProvider) {
CommandBus commandBus = SimpleCommandBus.builder().build();
commandBus.registerDispatchInterceptor(
new CatalogDispatchInterceptor(containerManagedEntityManagerProvider.getEntityManager()));
return commandBus;
}
}
public class CatalogDispatchInterceptor implements MessageDispatchInterceptor<CommandMessage<?>> {
private final EntityManager entityManager;
public CatalogDispatchInterceptor(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public BiFunction<Integer, CommandMessage<?>, CommandMessage<?>> handle(
List<? extends CommandMessage<?>> messages) {
return (index, command) -> {
(CreateCatalogCommand.class.isInstance(command.getPayloadType())) { }
return command;
};
}
}
The ContainerManagedEntityManagerProvider instance created by Axon, if you are using the Spring Boot Starter, through the JpaAutoConfiguration looks as follows:
#Bean
#ConditionalOnMissingBean
public EntityManagerProvider entityManagerProvider() {
return new ContainerManagedEntityManagerProvider();
}
Hence my first try would be to wire in a EntityManagerProvider instead of the ContainerManagedEntityManagerProvider. If that doesn't work, then you're dealing with a Spring bean ordering issue, which is somewhat out of the (axon) framework's scope I think. You could always just create the ContainerManagedEntityManagerProvider yourself of course, which i am pretty certain of will solve the problem at hand.
Hope either solution helps you out Aymen!
Related
I am totally confused about mixing of "wiring in JavaConfig" and "wiring using #Autowired". I will tell you my problems in 4 scenarios:
(I am ok with mixing of #Autowired and stereotype annotations and I don't have any question about that. my problem is Javaconfig and #autowired)
Scenario 1:
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer() {
cd = new CompactDisc() {
#Override
public void play() {
System.out.println("123456");
}
};
}
#Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
My JavaConfig File:
#Configuration
public class CDPlayerConfig {
#Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
#Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer();
}
}
For Example in this scenario, I see that #Autowired is effectless and cannot make Spring to invoke and use the parameterized constructor and no-arg constructor will be executed (because it is invoked in the #Bean method) and the output is the text "123456".
=================================================================
SCENARIO 2:
My JavaConfig File:
#Configuration
public class CDPlayerConfig {
#Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
#Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
}
we wired those two beans in the config file. and I know that we do not need #Autowired at all.
=================================================================
SCENARIO 3:
My JavaConfig File:
#Configuration
public class CDPlayerConfig {
#Bean()
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
#Bean
public CDPlayer cdPlayer() {
return new CDPlayer();
}
}
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
#Autowired
public void setCd(CompactDisc cd) {
this.cd = cd;
}
}
I know that if #Autowired is above of parameterized constructor, that constructor will not be executed but now that is above of setCd(), this method will be executed.
=================================================================
SCENARIO 4:
My JavaConfig File:
#Configuration
public class CDPlayerConfig {
#Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
#Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
My CDPlayer Class:
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
public CDPlayer() {
}
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play() {
cd.play();
}
#Autowired
public void doSomething(CompactDisc cd) {
this.cd = new CompactDisc() {
#Override
public void play() {
System.out.println("AAAAA");
}
};
}
}
and in this scenario, Although that we wired those two beans together, but #Autowired makes spring to execute the doSomething()method.
What is happening?! I can't see the Big Picture. I can't understand the pattern that is going on.
sometimes #Autowired works and sometimes doesn't work. what is the general pattern? do we need #Autowired at all when we wire beans together in JavaConfig file?
An autowired constructor is invoked if spring invokes the constructor by reflection, typically because you declare the bean using component scanning or XML config. If you manually invoke a constructor in a #Bean method, that constructor executes, and #Autowired has no effect.
An autowired method is invoked after the bean has been created, irrespective of how the bean was created.
The reason is that, in Java, each constructor call creates a new object, making it impossible to call two constructors for the same object. That's why Spring can't call a second constructor if you have already called a different one. In contrast, it is possible to call many methods on the same object, so Spring does support method autowiring just fine.
To conclude, you can use autowiring with JavaConfig, but you should autowire fields or methods rather than constructors. Or you can do without autowiring, and pass everything explicitly in your #Bean method. Or any mixture of the two.
The Spring Context contains all the beans you need in your program, and Spring do the rest of the job for you. But something to understand is that your beans comes from many parts of your application :
Internal beans (POJO from your domain).
External beans (POJO from other libraries or third partie classes).
Reading this from the spring documentation, you can find all the differents sources of beans :
#SpringBootApplication is a convenience annotation that adds all of
the following:
#Configuration: Tags the class as a source of bean definitions for the
application context.
#EnableAutoConfiguration: Tells Spring Boot to start adding beans
based on classpath settings, other beans, and various property
settings. For example, if spring-webmvc is on the classpath, this
annotation flags the application as a web application and activates
key behaviors, such as setting up a DispatcherServlet.
#ComponentScan: Tells Spring to look for other components,
configurations, and services in the com/example package, letting it
find the controllers.
Follow these rules :
In your domain classes (Controller, Service) : use #Autowired in your constructor. It is the recommanded way to inject your dependencies.
You want to use external classes : implements a Java Configuration with #Configuration annotation, to instanciate your external classes as beans.
You want to create custom utilities classes : decorate it with #Component.
When you have more than on implementation, use #Qualifier and define your beans in a #Configuration class.
I have following configuration:
#Qualifier1
#Qualifier2
#Bean
public MyBean bean1(){...}
#Qualifier2
#Qualifier3
#Bean
public MyBean bean2(){...}
#Qualifier1
#Qualifier2
#Qualifier3
#Bean
public MyBean bean3(){...}
#Qualifier3
#Bean
public MyBean bean4(){...}
#Qualifier1
#Bean
public MyBean bean5(){...}
And it is the injection place:
#Qualifier2
#Qualifier3
#Autowired:
private List<MyBean> beans;
By default spring uses AND logic for each #Qualifier
So bean2 and bean3 will be injected.
But I want to have OR logic for that stuff so I expect beans bean1 bean2 bean3 and bean4 to be injected
How can I achieve it?
P.S.
#Qualifier annotation is not repeatable so I have to create meta annotation for each annotation:
#Retention(RetentionPolicy.RUNTIME)
#Qualifier
public #interface Qualifier1 {
}
What if you used marker interfaces instead of qualifiers? For example:
public class MyBean1 extends MyBean implements Marker1 {}
public class MyBean2 extends MyBean implements Marker2 {}
public class MyBean12 extends MyBean implements Marker1, Marker2 {}
Then using this:
#Bean
public MyBean1 myBean1() {
//...
}
#Bean
public MyBean2 myBean2() {
//...
}
#Bean
public MyBean12 myBean12() {
//...
}
and this:
#Autowired private List<Marker1> myBeans;
You would get a list of myBean1 and myBean12 beans.
And for this:
#Autowired private List<Marker2> myBeans;
You would get a list of myBean2 and myBean12 beans.
Will this work?
UPDATE I
Custom FactoryBean
I implemented TagsFactoryBean class and #Tags annotation which you can use to solve your task (I hope :)).
First, mark your beans with #Tags annotation:
#Tags({"greeting", "2letters"})
#Bean
public Supplier<String> hi() {
return () -> "hi";
}
#Tags({"parting", "2letters"})
#Bean
public Supplier<String> by() {
return () -> "by";
}
#Tags("greeting")
#Bean
public Supplier<String> hello() {
return () -> "hello";
}
#Tags("parting")
#Bean
public Supplier<String> goodbye() {
return () -> "goodbye";
}
#Tags("other")
#Bean
public Supplier<String> other() {
return () -> "other";
}
Then prepare TagsFactoryBean:
#Bean
public TagsFactoryBean words() {
return TagsFactoryBean.<Supplier>builder()
.tags("greeting", "other")
.type(Supplier.class)
.generics(String.class)
.build();
}
Here tags is an array of desired tags whose beans should be selected, type is a selected beans type, and generics is an array of generic types of the beans. The last parameter is optional and should be used only if your beans are generic.
Then you can use it with #Qualifier annotation (otherwise Spring injects all beans of Supplier<String> type):
#Autowired
#Qualifier("words")
private Map<String, Supplier<String>> beans;
The Map beans will contain three beans: hi, hello and other (their name are keys of the Map and their instances are its values).
More usage examples you can find in tests.
UPDATE II
Custom AutowireCandidateResolver
Thanks to #bhosleviraj recommendation, I implemented TaggedAutowireCandidateResolver that simplifies the process of autowiring the desired beans. Just mark your beans and the autowired collection with the same tags and you will get them injected into the collection:
#Autowired
#Tags({"greeting", "other"})
private Map<String, Supplier<String>> greetingOrOther;
#Configuration
static class Beans {
#Tags({"greeting", "2symbols", "even"})
#Bean
public Supplier<String> hi() {
return () -> "hi";
}
#Tags({"parting", "2symbols", "even"})
#Bean
public Supplier<String> by() {
return () -> "by";
}
#Tags({"greeting", "5symbols", "odd"})
#Bean
public Supplier<String> hello() {
return () -> "hello";
}
#Tags({"parting", "7symbols", "odd"})
#Bean
public Supplier<String> goodbye() {
return () -> "goodbye";
}
#Tags({"other", "5symbols", "odd"})
#Bean
public Supplier<String> other() {
return () -> "other";
}
}
You can use not only the Map for injecting beans but also other Collections.
To make it work you have to register a CustomAutowireConfigurer bean in your application and provide it with TaggedAutowireCandidateResolver:
#Configuration
public class AutowireConfig {
#Bean
public CustomAutowireConfigurer autowireConfigurer(DefaultListableBeanFactory beanFactory) {
CustomAutowireConfigurer configurer = new CustomAutowireConfigurer();
beanFactory.setAutowireCandidateResolver(new TaggedAutowireCandidateResolver());
configurer.postProcessBeanFactory(beanFactory);
return configurer;
}
}
More usage examples see in this Test.
Answer requires deep understanding of how autowiring resolution is implemented in Spring, so we can extend it.
I couldn't come up with any solution yet, but I can give you some pointers.
Possible candidate to extend is QualifierAnnotationAutowireCandidateResolver , override method that resolves to a qualified bean. And pass the custom autowire resolver to the bean factory.
You can clone source code and correct version branch from here:
https://github.com/spring-projects/spring-framework
There is a CustomAutowireConfigurerTests in spring-beans module, that might help you understand few things.
I guess you can't do it by using annotation.
What I'd use is the org.springframework.context.ApplicationContextAware Maybe you need to write some extra code but in this way you can solve your issue.
I'd implement a class like this:
#Component
public class SpringContextAware implements ApplicationContextAware {
public static ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ctx = applicationContext;
}
public static synchronized ApplicationContext getCtx() {
return ctx;
}
}
Then in all beans where you need the OR logic you want you can do something like this:
#Autowired
private SpringContextAware ctxAware;
#PostConstruct
public void init() {
//Here you can do your OR logic
ctxAware.getCtx().getBean("qualifier1") or ctxAware.getCtx().getBean("qualifier2")
}
Will this solve your issue?
Angelo
In my Spring Boot 1.5.10 application with Spring Data REST and HATEOAS, I have a ResourceProcessor bean with an #Autowired service, like:
#Bean
public ResourceProcessor<Resource<Order>> orderResourceProcessor() {
return new ResourceProcessor<Resource<Order>>() {
#Autowired
private OrderHandler orderHandler;
#Override
public Resource<Order> process(Resource<Order> resource) {
Order order = resource.getContent();
Payment payment = orderHandler.payment(order);
resource.add(makeLink(payment));
return resource;
}
private Link makelink(Payment payment) {
return new Link(/*...*/);
}
};
}
When the #Autowired service is added, the resource processor bean is no longer triggered, unfortunately; i.e., when OrderHandler is commented out, the resource processor runs as it should.
Can a ResourceProcessor use #Autowired services; and, if so, what's the right way to construct it?
This part of the #Bean annotation javadoc should interest you :
#Bean Methods in #Configuration Classes
Typically, #Bean methods are declared within #Configuration classes.
In this case, bean methods may reference other #Bean methods in the
same class by calling them directly. This ensures that references
between beans are strongly typed and navigable. Such so-called
'inter-bean references' are guaranteed to respect scoping and AOP
semantics, just like getBean() lookups would.
Example :
#Bean
public FooService fooService() {
return new FooService(fooRepository());
}
#Bean
public FooRepository fooRepository() {
return new JdbcFooRepository(dataSource());
}
It means that you have not to use #Autowired to set the dependency inside the #Bean declaration but reference another method annotated with #Bean.
But do you really need to set the dependency to create your bean ?
No at all. The OrderHandler is used only during the process() invocation.
So you can simply inject OrderHandler at the same level that the method annotated with #Bean and using it in the anonymous class :
#Autowired
private OrderHandler orderHandler; // only change
#Bean
public ResourceProcessor<Resource<Order>> orderResourceProcessor() {
return new ResourceProcessor<Resource<Order>>() {
#Override
public Resource<Order> process(Resource<Order> resource) {
Order order = resource.getContent();
Payment payment = orderHandler.payment(order);
resource.add(makeLink(payment));
return resource;
}
private Link makelink(Payment payment) {
return new Link(/*...*/);
}
};
}
I guess you can Autowire orderHandler to outer class. In your way it will not work as you create the instance of ResourceProcessor yourself.
#Autowired
private OrderHandler orderHandler;
#Bean
public ResourceProcessor<Resource<Order>> orderResourceProcessor() {
return new ResourceProcessor<Resource<Order>>() {
#Override
public Resource<Order> process(Resource<Order> resource) {
Order order = resource.getContent();
Payment payment = orderHandler.payment(order);
resource.add(makeLink(payment));
return resource;
}
private Link makelink(Payment payment) {
return new Link(/*...*/);
}
};
}
I need to have a Spring dependency injected into a JPA entity listener. I know I can solve this using #Configurable and Spring's AspectJ weaver as javaagent, but this seems like a hacky solution. Is there any other way to accomplish what I'm trying to do?
Since Hibernate 5.3 org.hibernate.resource.beans.container.spi.BeanContainer and Spring 5.1 org.springframework.orm.hibernate5.SpringBeanContainer you do not need to extra autowiring effort any more. See details of this feature in https://github.com/spring-projects/spring-framework/issues/20852
Simply annotate your EntityListener class with #Component, and do any autowiring like so:
#Component
public class MyEntityListener{
private MySpringBean bean;
#Autowired
public MyEntityListener(MySpringBean bean){
this.bean = bean;
}
#PrePersist
public void prePersist(final Object entity) {
...
}
}
In Spring Boot the configuration of LocalContainerEntityManagerFactoryBean is done automatically in org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration.
Outside of Spring Boot, you have to register SpringBeanContainer to Hibernate:
LocalContainerEntityManagerFactoryBean emfb = ...
emfb.getJpaPropertyMap().put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory));
Another trick is to implement an utility class with static method that helps you to use Spring beans everywhere, not only in managed classes:
#Component
public final class BeanUtil {
private static ApplicationContext context;
private BeanUtil(ApplicationContext context) {
BeanUtil.context = context;
}
public static <T> T getBean(Class<T> clazz) throws BeansException {
Assert.state(context != null, "Spring context in the BeanUtil is not been initialized yet!");
return context.getBean(clazz);
}
}
Here's a solution in Kotlin (Spring Boot 2.3.9, Hibernate 5.4.29.Final). First part is similar to Matthias' answer. However, the second part was needed even though it's a Spring Boot application.
Bean declaration
#Component
class EntityXyzListener(val mySpringBean: MySpringBean) {
#PostLoad
fun afterLoad(entityXyz: EntityXyz) {
// Injected bean is available here. (In my case the bean is a
// domain service that I make available to the entity.)
entityXyz.mySpringBean= mySpringBean
}
}
Datasource configuration
I already had this datasource #Configuration in my spring boot app. I only had to add the line of code that puts the BEAN_CONTAINER property in the jpaPropertyMap.
#Resource
lateinit var context: AbstractApplicationContext
#Primary
#Bean
#Qualifier("appDatasource")
#ConfigurationProperties(prefix = "spring.datasource")
fun myAppDatasource(): DataSource {
return DataSourceBuilder.create().build()
}
#Primary
#Bean(name = ["myAppEntityManagerFactory"])
fun entityManagerFactoryBean(builder: EntityManagerFactoryBuilder): LocalContainerEntityManagerFactoryBean {
val localContainerEntityManagerFactoryBean =
builder
.dataSource(myAppDatasource())
.packages("com.mydomain.myapp")
.persistenceUnit("myAppPersistenceUnit")
.build()
// the line below was the long-sought solution :^)
localContainerEntityManagerFactoryBean.jpaPropertyMap.put(
AvailableSettings.BEAN_CONTAINER, SpringBeanContainer(context.beanFactory))
return localContainerEntityManagerFactoryBean
}
You can try this solution
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public final class AutowireHelper implements ApplicationContextAware {
private static final AutowireHelper INSTANCE = new AutowireHelper();
private static ApplicationContext applicationContext;
private AutowireHelper() {
}
/**
* Tries to autowire the specified instance of the class if one of the specified beans which need to be autowired
* are null.
*
* #param classToAutowire the instance of the class which holds #Autowire annotations
* #param beansToAutowireInClass the beans which have the #Autowire annotation in the specified {#classToAutowire}
*/
public static void autowire(Object classToAutowire, Object... beansToAutowireInClass) {
for (Object bean : beansToAutowireInClass) {
if (bean == null) {
applicationContext.getAutowireCapableBeanFactory().autowireBean(classToAutowire);
return;
}
}
}
/**
* #return the singleton instance.
*/
public static AutowireHelper getInstance() {
return INSTANCE;
}
#Override
public void setApplicationContext(final ApplicationContext applicationContext) {
AutowireHelper.applicationContext = applicationContext;
}
}
and then
#Autowired
SomeService thatToAutowire;
AutowireHelper.autowire(this, this.thatToAutowire);//this in the method
Extending a bit the above responses:
Since Hibernate 5.3 org.hibernate.resource.beans.container.spi.BeanContainer and Spring 5.1. You can use this to post process loaded domain entities for instance. Instead of using the aspect.
See:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/hibernate5/SpringBeanContainer.html
In your config:
#Bean
LocalContainerEntityManagerFactoryBean customCartEntityManagerFactory(DataSource customCartDataSource, EntityManagerFactoryBuilder builder, ConfigurableListableBeanFactory beanFactory) {
var mf = builder
.dataSource(customCartDataSource)
.packages("com.my.domain")
.build();
mf.getJpaPropertyMap().put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory));
return mf;
}
In your entity bean:
#EntityListeners(MyEntityListener.class)
The listener, notice no #Component decoration.
#Slf4j
public class MyEntityListener implements BeanFactoryAware, InitializingBean {
private final BeanConfigurerSupport beanConfigurerSupport = new BeanConfigurerSupport();
public CustomCartEntityListener() {
log.info("MyEntityListener created");
}
#PostLoad
public void postLoad(MyEntity entity) {
beanConfigurerSupport.configureBean(entity);
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanConfigurerSupport.setBeanWiringInfoResolver(new AnnotationBeanWiringInfoResolver());
this.beanConfigurerSupport.setBeanFactory(beanFactory);
}
#Override
public void afterPropertiesSet() {
this.beanConfigurerSupport.afterPropertiesSet();
log.info("MyEntityListener initialized");
}
}
Is there any way to have spring call a factory with a runtime parameter of the type of the parent class of a variable it is trying to autowire?
For example, let's say I have something like this:
interface IConfig {
}
interface IConfigProvider {
IConfig getConfig(Class<?> type)
}
class MyClass {
#Autowired
private IConfig _config;
}
Is there anyway to have spring, when autowiring MyClass._config to essentially call IConfigProvider.getConfig(MyClass.class) (well the concrete version that is in the context) at runtime to wire the variable?
I know I could autowire the factory and call it myself, I could even "hide" it in a base class but I am trying to avoid this.
NOTE: I am very new to Spring so if I am asking something really stupid/not using the right terminology, I apologise.
You would need to create a FactoryBean for that. Something like this should do the trick.
class IConfigFactoryBean implements FactoryBean<IConfig> {
#Autowired
private IConfigProvider configProvider;
private IConfig config;
#PostConstruct
public void initialize() {
config = configProvider.getConfig(...);
}
#Override
public IConfig getObject() throws Exception {
return config;
}
#Override
public Class<?> getObjectType() {
return ...;
}
#Override
public boolean isSingleton() {
return true;
}
}
I am not sure what the argument would be. Note that if you have several instances of IConfig you will need to qualify them as Spring won't be able to know which one it has to inject based on a simple #Autowired annotation. Check the javadoc of #Qualifier for more information.