Preferable way to use a bean in self-initialized objects in Spring - java

I've been working around Java and Spring(Batch, Boot), and have a question.
I created beans by Spring for generating a service class. I bind it with #Autowired annotation like this:
#Component
public class MyTaskRunner {
#Autowired
private MyService myService;
public void run() {
List<SomeObject> someObjects = myService.getSomeObjects();
// Do some tasks
}
}
Here, I also want to use such a bean in SomeObject which are deserialized from a database(meaning, not from Spring). I've looked for solutions here and am going to try them, but most of them seem elaborate, just for injecting a bean.
My question is: Is it so unusual usage of bean that it needs some work?
Thank you in advance! Any comments would be appreciated.

Related

Why is #Bean(initMethod="") not detecting given method in spring?

Edit Fixed by changing package.
I have this configuration file for spring framework
#Configuration
public class AppConfig {
#Bean(initMethod = "populateCache")
public AccountRepository accountRepository(){
return new JdbcAccountRepository();
}
}
JdbcAccountRepository looks like this.
#Repository
public class JdbcAccountRepository implements AccountRepository {
#Override
public Account findByAccountId(long
return new SavingAccount();
}
public void populateCache() {
System.out.println("Populating Cache");
}
public void clearCache(){
System.out.println("Clearing Cache");
}
}
I'm new to spring framework and trying to use initMethod or destroyMethod. Both of these method are showing following errors.
Caused by: org.springframework.beans.factory.support.BeanDefinitionValidationException: Could not find an init method named 'populateCache' on bean with name 'accountRepository'
Here is my main method.
public class BeanLifeCycleDemo {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new
AnnotationConfigApplicationContext(AppConfig.class);
AccountRepository bean = applicationContext.getBean(AccountRepository.class);
applicationContext.close();
}
}
Edit
I was practicing from a book and had created many packages for different chapters. Error was it was importing different JdbcAccountRepository from different package that did not have that method. I fixed it and it works now. I got hinted at this from answers.
Like you said, if you are mixing configurations types, it can be confusing. Besides, even if you created a Bean of type AccountRepository, because Spring does a lot of things at runtime, it can call your initMethod, even if the compiler couldn't.
So yes, if you have many beans with the same type, Spring can be confused an know which one to call, hence your exception.
Oh and by the way, having a Configuration creating the accountRepoisitory Bean, you can remove the #Repository from your JdbcAccountRepository... It is either #Configuration + #Bean or #Component/Repository/Service + #ComponentScan.
TL;DR
Here is more information and how Spring creates your bean : What object are injected by Spring ?
#Bean(initMethod = "populateCache")
public AccountRepository accountRepository(){
return new JdbcAccountRepository();
}
With this code, Spring will :
Detect that you want to add a Bean in the application Context
The bean information are retrieved from the method signature. In your case, it will create a bean of type AccountRepository named accountRepository... That's all Spring knows, it won't look inside your method body.
Once Spring is done analysing your classpath, or scanning the bean definitions, it will start instanciating your object.
It will therefor creates your bean accountRepository of type AccountRepository.
But Spring is "clever" and nice with us. Even if you couldn't write this code without your compiler yelling at you, Spring can still call your method.
To make sure, try writing this code :
AccountRepository accountRepository = new JdbcAccountRepository();
accountRepository.populateCache(); // Compiler error => the method is not found.
But it works for Spring... Magic.
My recommandation, but you might thinking the same now: If you have classes across many packages to answer different business case, then rely on #Configuration classes. #ComponentScan is great to kickstart your development, but reach its limit when your application grows...
You mix two different ways of spring bean declaration:
Using #Configuration classes. Spring finds all beans annotated with #Configuration and uses them as a reference to what beans should be created.
So if you follow this path of configuration - don't use #Repository on beans. Spring will detect it anyway
Using #Repository - other way around - you don't need to use #Configuration in this case. If you decide to use #Repository put #PostConstruct annotation on the method and spring will call it, in this case remove #Configuration altogether (or at least remove #Bean method that creates JdbcAccountRepository)
Annotate populateCache method with #PostConstruct and remove initMethod from #Bean. It will work.

Does Spring's #RequestScope automatically handle proxying when injected in singleton beans?

I'm using a Java8/Spring Boot 2 application. I want to inject a request-scoped bean into a singleton bean. The official documentation highlights that either a proxy or ObjectFactory/Provider should be used to ensure always getting the correctly scoped bean at runtime in the singleton bean. However, the #RequestScope annotation seems to "automatically" set some kind of proxy, as explained in the answer to this question.
I'm now wondering if the following three implementations are in fact identical and which one is preferred?
Approach 1: explicitly using objectFactory<>
#Component
#RequestScope
public class MyRequestScopedBean{...}
#Component
public class MySingletonBean{
#Autowired
private ObjectFactory<MyRequestScopedBean> myRequestScopedBean
}
Approach 2: inject normally, assuming the request scoped bean is proxied automatically?
#Component
#RequestScope
public class MyRequestScopedBean{...}
#Component
public class MySingletonBean{
#Autowired
private MyRequestScopedBean myRequestScopedBean
}
Approach 3: using #Configuration and #Bean because I don't know the difference and I'm worried they behave differently.
#Comfiguration
public class myBeanConfig{
#Bean
#RequestScope
public MyRequestScopedBean getRequestScopedBean(){return new MyRequestScopedBean();}
}
#Component
public class MySingletonBean{
#Autowired
private MyRequestScopedBean myRequestScopedBean
}
I would prefer approach 2, because it is concise and handles the scoping/proxying automatically.
Would the answer change if my #Autowired bean is declared as a final field? I'm worried making it final somehow prevents the proxy from fetching the correctly fetching the new bean every request.
I have been using the 2nd approach in my projects and I have zero issues so far. The documentation does not mention it's a MUST to use ObjectFactory too. Don't think too much. If you run into any problems, you will see the error very clearly in the console. There's no reason to be afraid until you have an actual issue to deal with.
Yes, with #RequestScope the proxy is already default activated, the effect exactly equal to #Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyModel = ScopedProxyMode.TARGET_CLASS)

Injecting List of Prototypes into Singleton bean in Spring

Need some help in spring here.
In our project we use XML and annotation configurations (Spring 4.1)
Recently I've faced the following task:
I have a list of beans of scope prototype, all of them implement the same interface.
In addition I have one singleton bean that has execute method. Inside the method the bean should access the list of those prototype beans.
Every time the 'execute' method gets executed I would like to get the access to the different instances of those prototype beans).
In singleton I don't have the whole list of beans known in advance, so I just #Autowire the whole collection so that every bean implementation known in the application context will be loaded.
interface SomeInterface {
}
class PrototypeBean1 implements SomeInterface {
...
}
class PrototypeBean2 implements SomeInterface {
...
}
class MySingletonBean {
#Autowire (????)
List<SomeInterface> allPrototypeBeansLoadedIntoTheApplicationContext;
public void execute() {
// this one is called many times,
// so I would like to get different lists of
//"allPrototypeBeansLoadedIntoTheApplicationContext"
// with different actuals bean upon every invocation
// how do I achieve this???
}
}
So my question is: What is the most clean way to achieve this? Ideally I would like to get a solution totally decoupled from spring interfaces (like injecting ApplicationContext/BeanFactory stuff)
I don't mind to use Aop here (performance is not that critical), but I can't really wrap my head around a clean spring solution. So any help will be appreciated.
Thanks in advance
I have been trying to achieve similar goal with Spring and after reading Spring docs using either ServiceLocatorFactoryBean or method injection (with #Lookup) came up and looked promising.
However after tried both approach results turned out to be frustrating. Neither way supports returning beans in List. And I got this exception:
No qualifying bean of type 'java.util.List' available
Apparently Spring treated the return type as a regular Object.
So eventually my solution became creating a new object to wrap the list as return type.
#Component
#Scope("prototype")
public class ProcessorList
{
private List<Processor> processors;
public ProcessorList(List<Processor> processors)
{
this.processors = processors;
}
public List<Processor> getProcessors()
{
return processors;
}
public void setProcessors(List<ChangeSetProcessor> processors)
{
this.processors = processors;
}
}
then create a Factory class for the List Object:
#Component
public interface ProcessorFactory
{
ProcessorList getProcessorList();
}
Then use ServiceLocatorFactoryBean to register the factory:
#Configuration
public class MyConfiguration{
#Bean
public FactoryBean serviceLocatorFactoryBean()
{
ServiceLocatorFactoryBean factoryBean = new ServiceLocatorFactoryBean();
factoryBean.setServiceLocatorInterface(ProcessorFactory.class);
return factoryBean;
}
}
Finally implement the interface and make sure mark them all with #Scope("prototype")
Now you'll get new instance each time you use the factory method!
It's similar to use method injection if you prefer.

Can #Autowire #Service beans but not members of a class instantiated with "new" keyword - even with context scanning configured

I have an app that's been working well with #Autowired #Service beans.
Now I'm adding a Validator class which is instantiated in the Controller:
BlueValidator validator = new BlueValidator(colors);
validator.validate(colorBlend, bindResult);
In the BlueValidator class I'm trying to #Autowire the blendService which is working as an #Autowired field elsewhere in the app:
public class BlueValidator implements Validator {
#Autowired
private BlendService blendService;
private Colors colors;
But for some reason after instantiating the BlueValidator, I keep getting NullPointerExceptions for the blendService.
Of course I've added the necessary context scanning:
<context:component-scan
base-package="com.myapp.controllers, com.myapp.services, com.myapp.validators" />
I also tried adding the#Autowired annotation to the constructor but that didn't help:
#Autowired
public BlueValidator(Colors colors) {
this.colors = colors;
}
Should I just pass the blendService to the BlueValidator and forget about the Autowiring or is there something obvious missing here?
If you just instantiate an object with new, Spring is not involved, so the autowiring won't kick in. Component scanning looks at classes and creates objects from them - it doesn't look at objects you create yourself.
This can be made to work, using Spring's AspectJ support, but it takes some effort.
Otherwise, you need to let Spring instantiate your objects if you wan autowiring to work.
Should I just pass the blendService to the BlueValidator and forget about the Autowiring
In your situation, I'd say yes, this is the least effort solution.
When you instantiate objects spring cannot do anything for them, so it does not get the dependencies injected (article).
In your case, you have a couple of options:
pass dependencies to the validator from the controller (where you can inject them)
make the validator a spring bean and inject it, instead of instantiating it
use #Configurable, which, via AspectJ, enables spring injection even in objects created with new
#Autowired is being used by Spring's ApplicationContext to populate those fields on creation. Since the ApplicationContext is not the one creating these beans (you are because of the keyword 'new'), they are not being autowired. You need to pass it in yourself if you are creating it.
Don't create validator manually -- allow to Spring do this work for you:
#Controller
class Controller {
#Autowired
BlueValidator validator;
void doSomething() {
...
validator.validate(colorBlend, bindResult);
...
}
}
Also pay attention that adding package com.myapp.validators to context:scan-packages not enough, you also should annotate your validator class with #Component annotation:
#Component
public class BlueValidator implements Validator {
#Autowired
private BlendService blendService;
(BTW this solution works in my project.)

Self injection with Spring

I tried the following code with Spring 3.x which failed with BeanNotFoundException and it should according to the answers of a question which I asked before - Can I inject same class using Spring?
#Service
public class UserService implements Service{
#Autowired
private Service self;
}
Since I was trying this with Java 6, I found the following code works fine:
#Service(value = "someService")
public class UserService implements Service{
#Resource(name = "someService")
private Service self;
}
but I don't understand how it resolves the cyclic dependency.
EDIT:
Here's the error message. The OP mentioned it in a comment on one of the answers:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring.service.Service] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Update: February 2016
Self autowiring will be officially supported in Spring Framework 4.3. The implementation can be seen in this GitHub commit.
The definitive reason that you cannot autowire yourself is that the implementation of Spring's DefaultListableBeanFactory.findAutowireCandidates(String, Class, DependencyDescriptor) method explicitly excludes the possibility. This is visible in the following code excerpt from this method:
for (String candidateName : candidateNames) {
if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
result.put(candidateName, getBean(candidateName));
}
}
FYI: the name of the bean (i.e., the bean that's trying to autowire itself) is beanName. That bean is in fact an autowire candidate, but the above if-condition returns false (since candidateName in fact equals the beanName). Thus you simply cannot autowire a bean with itself (at least not as of Spring 3.1 M1).
Now as for whether or not this is intended behavior semantically speaking, that's another question. ;)
I'll ask Juergen and see what he has to say.
Regards,
Sam (Core Spring Committer)
p.s. I've opened a Spring JIRA issue to consider supporting self-autowiring by type using #Autowired. Feel free to watch or vote for this issue here: https://jira.springsource.org/browse/SPR-8450
This code works too:
#Service
public class UserService implements Service {
#Autowired
private ApplicationContext applicationContext;
private Service self;
#PostConstruct
private void init() {
self = applicationContext.getBean(UserService.class);
}
}
I don't know why, but it seems that Spring can get the bean from ApplicationContext if is created, but not initialized. #Autowired works before initialization and it cannot find the same bean. So, #Resource maybe works after #Autowired and before #PostConstruct.
But I don't know, just speculating. Anyway, good question.
By the way, the more elegant solution to the self-invocation problem is to use AspectJ Load-Time Weaving for your transactional proxies (or whatever AOP-introduced proxy you're using).
For example, with annotation-driven transaction management, you can use the "aspectj" mode as follows:
<tx:annotation-driven mode="aspectj" />
Note that the default mode is "proxy" (i.e., JDK dynamic proxies).
Regards,
Sam
Given above code I don't see a cyclic dependency.
You injecting some instance of Service into UserService.
The implementation of the injected Service does not necessarily need to be another UserService so there is no cyclic dependency.
I do not see why you would inject a UserService into UserService but I'm hoping this is a theoretic try out or such.
Get AOP proxy from the object itself question suggests alternative hacky approach with AopContext.currentProxy() that may be suitable for special cases.
Just another aproach:
#EnableAsync
#SpringBootApplication
public class Application {
#Autowired
private AccountStatusService accountStatusService;
#PostConstruct
private void init() {
accountStatusService.setSelf(accountStatusService);
}
}
#Service
public class AccountStatusService {
private AccountStatusService self;
public void setSelf(AccountStatusService self) {
this.self = self;
}
}
with this your service will be in proxy. I did this to work with async methods inside itself.
I have tryied #sinuhepop solution:
#PostConstruct
private void init() {
self = applicationContext.getBean(UserService.class);
}
It did a injection but the service wasn't inside proxy and my methods wasn't running on a new thread. With that aproach it works as i would like.
It looks like spring creates and configures an object and then places it in the bean look up context. But, in the case of Java, I think it creates the object and ties it to the name and the during configuration when the object is looked up by the name it is found in the context.
This is my solution for small to medium sized projects. No AspectJ or application context magic, it works with singletons and constructor injection and is very easy to test.
#Service
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {
private final PersonDao _personDao;
#Autowired
public PersonDao(PersonDao personDao) {
_personDao = personDao;
}
}

Categories