I'm using Kinesis Client Library (KCL) and Spring boot. To use KCL, I have to implement a class (I named it RecordProcessor) for interface IRecordProcessor. And KCL will call this class and process records from kinesis. But when I tried to use dependency injection, I found it was not succeeded.
Here's the snippet for RecordProcessor:
#Component
public class RecordProcessor implements IRecordProcessor {
#Autowired
private SingleRecordProcessor singleRecordProcessor;
#Override
public void initialize(String shardId) {
...
}
#Override
public void processRecords(List<Record> records, IRecordProcessorCheckpointer checkpointer) {
...
}
}
I use Class SingleRecordProcessor to process single each record from kinesis. And this is my SingleRecordProcessor class snippet:
#Component
public class SingleRecordProcessor {
private Parser parser;
private Map<String, Table> tables;
public SingleRecordProcessor() {
}
#Autowired
private void setParser(Parser parser) {
this.parser = parser;
}
#Autowired
private void setTables(Map<String, Table> tables) {
this.tables = tables;
}
public void process(String record) {
...
}
}
I want to let spring framework automatically inject the SingleRecordProcessor instance into the class and use it. But I found that the field singleRecordProcessor is null.
Any idea why the dependency injection is failed? Or is it impossible to inject dependencies into a class which is called by other framework (in this case it's KCL)? Any suggestions will be appreciated! Really need some help please!!
[UPDATE]:
Sorry for not expressing the error clearly. The error was NullPointerException. I tried to inject singleRecordProcessor and call method process() on it. I think the injection was not successful so the instance singleRecordProcessor is null and there comes the NullPointerException.
More information is as follows:
I have a major class called Application
#SpringBootApplication
public class Application{
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.addListeners(new ApplicationPidFileWriter("./app.pid"));
ConfigurableApplicationContext ctx = application.run(args);
}
}
And I have the MainProcessor class which will call KCL.
#Service
public final class MainProcessor {
#EventListener(ApplicationReadyEvent.class)
public static void startConsumer() throws Exception {
init();
IRecordProcessorFactory recordProcessorFactory = new RecordProcessorFactory();
Worker worker = new Worker(recordProcessorFactory, kinesisClientLibConfiguration);
...
worker.run(); // this line will call KCL library and eventually call ProcessorRecord class.
}
}
[UPDATE2]
RecordProcessorFactory only has one method like this
#Component
public class RecordProcessorFactory implements IRecordProcessorFactory {
#Autowired
RecordProcessor recordProcessor;
#Override
public IRecordProcessor createProcessor() {
return recordProcessor;
}
}
It creates a new RecordProcessor instance for KCL to use it.
You should autowire an instance of this into your MainProcessor:
#Component
public class RecordProcessorFactory {
#Lookup IRecordProcessor createProcessor() { return null; }
}
Spring will instantiate a RecordProcessorFactory for you, and replace the implementation of createProcessor() in it with one that will return a new IRecordProcessor each time it's called. Both the factory and the processors will be Spring beans - which is what you want.
I am newbie in Spring and trying to understand AOP. Here's what I got
I have one simple aspect, which I want to run when any non-getter method gets called
#Aspect
#Component
public class LoggingAspect {
#Pointcut("execution(* org.practice.entity.Person.get*())")
private void getter() {}
#Before("!getter()")
public void noGetter() {
System.out.println("NO GETTER GETS CALLED");
}
}
Person class is simply
#Component
public class Person {
public void getPerson() {
System.out.println("GETTING PERSON....");
}
}
I am initializing the config using Java annotations
#Configuration
#EnableAspectJAutoProxy
#ComponentScan("org.practice")
public class DemoConfig {}
And then in my main method i have
public class MyApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class);
context.close();
}
}
As you can see I am simply creating a context and closing it and not calling any getter or non-getter method. When I run the program, I got the following console output
NO GETTER GETS CALLED....
This makes semi-sense as I am not calling any getter method, but I expected this aspect to execute only if I am explicitly calling any non-getter not by just opening the context. Please let me know if I want my business logic to execute only if any non-getter method gets invoked then how would I do it?
Thanks
Try this:
#Pointcut("execution(* org.practice.entity.Person.*())")
private void methodCall() {}
#Before("!getter() && methodCall")
public void noGetter() {
System.out.println("NO GETTER GETS CALLED");
}
I think its happening during the initializing of Person bean at the time od application context loading
Since you have given joinpoint as not of getter so at the time of default construction execution (provided by compiler) the advice is getting triggered
I need to initialize beans in the Spring context after my application has started; currently, I initialize beans in a class with annotation #Configuration like this:
#Configuration
public class AppConfig {
#Inject
#Bean
public BeanA init(param1, param2, etc...) {
--- Code to construct bean A ---
}
#Inject
#Bean
public BeanB init(param1, param2, etc...) {
--- Code to construct bean B ---
}
}
But some beans I need to initialize after application startup so my approach is create a class listen to ApplicationReadyEvent event in Spring and put the code to initialize beans in that class.
#Configuration
class ApplicationStartingListener implements ApplicationListener<ApplicationReadyEvent>{
---- Code to init bean here ----
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
--- If I put init bean code in here, is it correct? ----
}
}
Is this the best way? Or there are some other better solutions?
I will enumerate other approaches in order to init beans, I grouped the approach in Standard Approach and Spring Boot Approach.
Standard Approach
#PostConstruct: it is just an annotation that triggers a method after bean is create, it doesn't allow input parameters.
#Bean(init-method="somInitMehotd"): this approach is totally related to Spring bean lifecycle and it is called after bean creation, if you are using another method with #PostConstruct annotation, then the #PostConstruct will be called first. This approach doesn't allow input parameters.
ApplicationListener: this interface allows to listen the standard events related to the Context Lifecycle, also it can listen customized events. For example: create a class MyAppListener and implements ApplicationListener<ContextRefreshedEvent> in this case the MyAppListener will implement an onApplicationEvent method that receives a ContextRefreshedEvent
Spring Boot Approach
The runners: There are two very useful interfaces CommandLineRunner and ApplicationRunner both of them will run after ApplicationContext is created both of them allows to inject beans as input parameters.
Spring boot listeners: Spring Application gives some additional events than the standards events that comes from the Application Context. One of the event is ApplicationReadyEvent and it is fire when the application is ready to receive request. In order to listen this events just implements the ApplicationListener using ApplicationReadyEvent as generic.
Here is the example:
MyBean class has different methods that will be called for each approach listed above, every method will call a print method and that method has a Thread.sleep in order to validate the order that every listener is called.
import javax.annotation.PostConstruct;
public class MyBean {
private String myVar="";
public MyBean(){
}
#PostConstruct
public void postConstructInit(){
this.myVar="Post init called";
print();
}
public void beanInit(){
this.myVar="Bean init called";
print();
}
public void contextInit(){
this.myVar="Context init called";
print();
}
public void runnerInit(){
this.myVar="Runner init called";
print();
}
public void bootListenerInit(){
this.myVar="Boot init called";
print();
}
public void print(){
System.out.println(this.myVar);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Here is the ContextRefreshListener class that will listen the ContextRefreshedEvent and handle it.
public class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
contextRefreshedEvent.getApplicationContext().getBean(MyBean.class).contextInit();
}
}
And it is the BootListener that will receive the ApplicationReadyEvent that comes from Spring Application.
public class MyBootListener implements ApplicationListener<ApplicationReadyEvent> {
#Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
applicationReadyEvent.getApplicationContext().getBean(MyBean.class).bootListenerInit();
}
}
And finally the Spring Boot Application
#SpringBootApplication
public class StackoverflowBootApplication {
public static void main(String[] args) {
SpringApplication.run(StackoverflowBootApplication.class, args);
}
#Bean(name = "myBean", initMethod = "beanInit")
public MyBean getMyBean(){
return new MyBean();
}
#Bean
public ContextRefreshListener getContextRefreshedListener(){return new ContextRefreshListener();}
#Bean
public MyBootListener getBootListener(){return new MyBootListener();}
#Bean
public CommandLineRunner getRunner(ApplicationContext ctx){
return (args) -> {
ctx.getBean(MyBean.class).runnerInit();
};
}
}
The output is:
Post init called
Bean init called
Context init called
Runner init called
Boot init called
Post init called output comes from
#PostConstruct
public void init(){
this.initByPostconstruct="Post init called";
Bean init called comes from the initMethod value
#Bean(name = "myBean", initMethod = "beanInit")
public MyBean getMyBean(){
return new MyBean();
}
}
Context init called comes from ContextRefreshedEvent
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
contextRefreshedEvent.getApplicationContext().getBean(MyBean.class).contextInit();
}
Runner init called comes from CommandLineRunner
#Bean
public CommandLineRunner getRunner(ApplicationContext ctx){
return (args) -> {
ctx.getBean(MyBean.class).runnerInit();
};
}
Boot init called comes from ApplicationReadyEvent
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
applicationReadyEvent.getApplicationContext().getBean(MyBean.class).bootListenerInit();
}
All the listed scenarios were triggered by Spring, I didi'nt call any of the events directly, all of them were called by Spring Framework.
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;
}
}
This occurs when I subclass an #Configuration annotated class, and feed this to the AnnotationConfigApplicationContext
These classes below summarize the scenario. Here is the full source
public class Bar {}
public class Foo {
private Bar bar;
public Foo(Bar bar) { this.bar = bar; }
#Override public String toString() {
return super.toString() + "(" + bar + ")";
}
}
#Configuration
public class BaseAppConfig {
#Bean public Foo foo() { return new Foo(bar()); }
#Bean public Bar bar() { return new Bar(); }
}
/** Omitting #Configuration here */
public class AppConfig extends BaseAppConfig {
#Bean #Override public Bar bar() { return new Bar(); }
}
public class App {
public static void main(String[] args) {
try (AnnotationConfigApplicationContext ctx = new
AnnotationConfigApplicationContext(AppConfig.class)) {
System.out.println(ctx.getBean(Foo.class).toString());
System.out.println(ctx.getBean(Bar.class).toString());
}
}
}
This prints two Bar instances where I expect to see the same instance two times:
Foo#3e9b1010(Bar#6c3708b3)
Bar#6f1fba17
Because you are omitting the #Configuration annotation (and because it isn't #Inherited)
/** Omitting #Configuration here */
public class AppConfig extends BaseAppConfig {
Specifying the class in the AnnotationConfigApplicationContext
AnnotationConfigApplicationContext ctx = new
AnnotationConfigApplicationContext(AppConfig.class)
marks it as a regular bean class, not a #Configuration bean class.
This means that #Bean methods are operating in lite mode.
In contrast to the semantics for bean methods in #Configuration
classes, 'inter-bean references' are not supported in lite mode.
Instead, when one #Bean-method invokes another #Bean-method in lite
mode, the invocation is a standard Java method invocation; Spring does
not intercept the invocation via a CGLIB proxy. This is analogous to
inter-#Transactional method calls where in proxy mode, Spring does not
intercept the invocation — Spring does so only in AspectJ mode.
Emphasis mine. It means that this that the bar() call in
return new Foo(bar());
is really just calling bar() again, it isn't returning the old instance created.
#Configuration works by having Spring create a proxy of your annotated class which caches the instances returned by #Bean factory methods. Since you've removed #Configuration, Spring doesn't apply this caching and method calls work normally, in your case returning a new instance.
Rather than use direct Bar object creation you should use spring bean management:
#Configuration
public class BaseAppConfig {
#Bean #Autowired public Foo foo(Bar bar) { return new Foo(bar); }
#Bean public Bar bar() { return new Bar(); }
}
See spring reference for details.