I currently have numerous classes with a field like
private MyStuff myStuff = new MyStuff();
It would be preferable if there was a MyStuff singleton which all the classes used. Our project has a MyConfiguration class with some Beans in it, but they don't seem to get used, at least not directly, so I can't use them for examples. I have been tasked to create a MyStuff bean in the MyConfiguration class, and then inject it into my other classes.
What I have so far:
#Configuration
public class MyConfiguration
{
#Bean
public MyStuff myStuff()
{
return new MyStuff();
}
}
public SomeClass
{
public void dealWithStuff()
{
someStuff.myMethod();
}
#Autowired
private MyStuff someStuff;
}
This compiles but does not run. someStuff is null when it tries to call myMethod(). Apparently it does not see the bean or make the connection. What am I missing?
I'm going to make an assumption, so correct me if I'm wrong: you are creating instances of SomeClass yourself. Something like
SomeClass someInstance = new SomeClass();
outside of any Spring component.
In this case, how do you expect Spring to inject anything since it's not even process it.
You need to let Spring create objects (beans) that need to have other beans injected.
The problem is naming. Refer to this for a complete description but briefly it says
If you intend to express annotation-driven injection by name, do not primarily use #Autowired, even if is technically capable of referring to a bean name through #Qualifier values. Instead, use the JSR-250 #Resource annotation, which is semantically defined to identify a specific target component by its unique name, with the declared type being irrelevant for the matching process.
It means that you should be doing something like this:
#Resource(name="myStuff")
public void setSomeStuff(MyStuff someStuff){
this.someStuff = someStuff;
}
The reason is that you have defined your bean as myStuff but referring it as someStuff.
Also to have a singleton instance, all you need is to define its scope as singleton in your Spring Configuration as following:
#Configuration
public class MyConfiguration
{
#Bean #Scope(BeanDefinition.SCOPE_SINGLETON)
public MyStuff myStuff()
{
return new MyStuff();
}
}
As I see in your code, your object reference name is "someStuff" but you are referring to myStuff you should use someStuff.myMethod();
Related
I wanna switch from xml based spring configuration into java-based. For constructor type injection it is easy. Example I am using:
#Configuration
public class BeanConfiguration {
#Bean
public GreetingService greetingService(GreetingDao greetingDao) {
return new GreetingService(greetingDao);
}
#Bean
public GreetingDao greetingDao() {
return new GreetingDao();
}
}
However, when I want to inject through setter method I am doing something like this:
#Configuration
public class BeanConfiguration {
#Bean
public MeetingDao meetingDao() {
return new MeetingDao();
}
#Bean
public MeetingService meetingService(MeetingDao meetingDao) {
MeetingService meetingService = new MeetingService();
meetingService.setMeetingDao(meetingDao);
return meetingService;
}
}
I am not sure if this is a possible way to inject with Java-based Configuration and setter method. Unfortunately I cannot find any example (for constructor dependencies a lot of examples exists). Also I am not sure in case of Java-based configuration when should I use constructor and when setter. In Spring docs it is described that I should use constructor for required and setter for optional dependency. However, I see it as the same result for this kind of approach.
Thanks for any clarification.
Adam
Under the assumption that you cannot change the classes themselves, you could always just not return the bean until you have injected all the values.
#Configuration
public class YourConfig{
#Value("${some.value.from.properties}")
private String someValue;
#Bean
#Autowired
public YourBean yourBean(TheDependency theDependency){
YourBean bean = new YourBean();
bean.setTheDependency(theDependency);
bean.setSomeValue(someValue);
return bean;
}
}
Constructor injection is always preferred with class dependencies, but not always possible.
If you have access to changing the source for these services and beans you are creating, then I suggest using constructor injection and placing "#Service" on the class and "#Autowired" on the constructors.
Properties are an example of "optional" dependencies; it is common to default values and behavior if not provided. I prefer just placing the "#Value" directly on that field instead of my constructor because otherwise you might end up with WAY too many parameters. This is "setter" injection, but you don't want an actual setter method (again, not normally anyways); you only want Spring to change the value, not any of your other code.
Using "#Value" is fine if you only have one or two properties(or 3? It's not an exact science); however, if you find you have a lot of fields with "#Value" then you should use a configuration bean instead. An "#ConfigurationProperties" bean can also be treated the same way with "setter" injection, but I prefer constructor injection to be sure that at least the bean is never null, even though it's values might be.
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.
I have a class that has some dynamic attributes which I received on the constructor.
Other properties on this same class are/can be injected by spring.
I want to know if this is possible and how should I config my application. I using spring 3 and xml configuration.
Here is an example:
class MyClass {
private MyClass2 obj2; // should be injected by spring
private Long myId;
public MyClass(Long dynamicId) {
myId = dynamicId;
}
public void doSomehting() {
obj2.doOtherStuff(this);
}
}
So, what I want, since I must create MyClass dynamically, is that after I call new MyClass(1234), the obj2 gets injected by Spring.
Is it possible?
use an ObjectFactory to retrieve the bean from the di-container. If you wrap this factory in a factory object of your own, you can set any property and still have the bean managed by Spring. Since you want the bean to have some dynamically set property think it through whether you need a singleton-scoped bean (default) or a prototype one.
If you intend to do this from xml config you need to muck around with objectfactorycreatingfactorybean. Spring documentation is excellent, just follow the example.
If you do annotation-based configuration, you just need to autowire the ObjectFactory. Note that YourClass has to be declared as a bean too!
I'm pretty sure that's not possible. It looks like you want a (scary music) factory.
class MyClassFactory {
private final MyClass2 object;
public(MyClass2 object) {
this.object = object;
}
public createMyClass(Lond id) {
return new MyClass(id, object);
}
}
If you create an instance of MyClass dynamically with the new operator, that instance is outside of Spring's bean factory, so Spring cannot inject anything. You really have two options, from what I can see.
1) Make MyClass a prototype bean so Spring gives you a new instance every time you need it. You would need to then define obj2 as a property to be set (or Autowired).
2) Inject obj2 via Spring into the class that is creating the instance of MyClass and make obj2 a constructor argument so you have to inject it.
My 0.02 from what I read from your question. A note of caution, when creating a new instance in Java, it is always outside the bean factory and all work performed outside the bean factory looses the Spring proxy behaviors. Be very careful here, you can get yourself into a rabbit hole that can be hard to track down.
In my code, I don't want to load all the beans defined in the XXApplicationConfig class.
XXApplicationConfig is a #Configuration annotated file which has bunch of spring beans defined.
So, I want to load only AppBean from XXApplicationConfig class while testing to reduce loading test time and also differentiate what I am testing. I also want to load the class using XXApplicationConfig class to make sure the bean configuration defined is correct as well.
This is my Test class ( modified ) to test AppBean class.
Could you let me know if this is the right approach and suggest how to make it better? Currently, this approach seems to be working. But, not sure if it is correct way of approaching it.
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class ApplicationTest {
#Configuration
#PropertySources(value = {#PropertySource("classpath:test.properties")})
static class MyTestConfiguration {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public XXApplicationConfig xxAppConfig() {
return new XXApplicationConfig();
}
#Bean
public CustomTestService customTestService() {
return new CustomTestService();
}
#Bean
public AppBean appBean() throws Exception {
return XXApplicationConfig().appBean();
}
}
#Autowired
private AppBean appBean;
#Test
public void testAppBean() {
test appBean.doSomething();
}
}
If you want to test just one object, just create one object of that class, using the constructor of that class. Spring beans are designed to be POJOs. The Spring context is just a convenient way of creating and connecting objects. Nothing stops you creating and connecting them yourself.
If you can instantiated the class you want to test and manually inject all the dependencies it required via constructor and/or setter getters, then you don't need to use Spring in your test.
However, if your bean:
uses private fields annotated with #Autowired or #Value without corresponding getters/setters.
depends on many other beans.
the behavior you want to test depends on Spring AOP/Proxies (you use #Transactional or #Cacheable for example).
Then you will need Spring to wired the bean. I personally prefer to define a a minimal #Configuration class for these cases.
Then again, if your bean meets the conditions on the list you should consider refactoring the bean to minimize its dependencies and facilitate testing.
Is it possible to use #Configurable on a class that's weaved using AspectJ and get Spring to load in values on fields/methods which are annotated with #Value?
I know its possible with #Autowired and #Resource etc... Are there any others.
e.g.
#Configurable
public Class MyObj{
#Value("$(my.prop)")
private String aField;
public String getAField(){
return aField;
}
}
And then have something like
public aMethodSomewhereElse(){
MyObj obj = new MyObj()
assertNotNull(obj.getAField());
}
Are there any alternatives to being able to create MyObj with the new operator and still get spring to handle the annotations?
--EDIT:--
It IS possible to do this using new when using #Autowired, have a look at some Hibernate and JPA stuff with Spring and AOP... I've used this in the past to do some profiling of Java code. But I really want to use SPEL and #Value before I mock up a full example I was hoping to find the answer here. FYI - if you don't belive me the Spring Manual even says it is possible to do this, what I want to know is if its possible to use #Value annotations in the same scope...
The Spring container instantiates and configures beans defined in your
application context. It is also possible to ask a bean factory to
configure a pre-existing object given the name of a bean definition
containing the configuration to be applied. The spring-aspects.jar
contains an annotation-driven aspect that exploits this capability to
allow dependency injection of any object.
And...
Using the annotation on its own does nothing of course. It is the
AnnotationBeanConfigurerAspect in spring-aspects.jar that acts on the
presence of the annotation. In essence the aspect says "after
returning from the initialization of a new object of a type annotated
with #Configurable, configure the newly created object using Spring in
accordance with the properties of the annotation". In this context,
initialization refers to newly instantiated objects (e.g., objects
instantiated with the 'new' operator) as well as to Serializable
objects that are undergoing deserialization (e.g., via readResolve()).
http://static.springsource.org/spring/docs/3.0.0.RC2/reference/html/ch07s08.html
Cheers.
You are absolutely right - #Autowired fields will be wired in an #Configurable annotated class even outside of a Spring container, assuming that you have a AspectJ infrastructure in place.
You have noted a good catch though, #Value fields are processed by a Spring bean post processor(AutowiredAnnotationBeanPostProcessor), which resolves the #Value annotated fields. It does not act on objects instantiated outside of the container though - so in short, the #Autowired fields should get wired in, but #Value properties will not.
Doing
MyObj obj = new MyObj()
means that obj is not managed by spring, so it will not do autowiring.
Only way to do that is to obtain instance from an application context. For example:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyObj obj = context.getBean("myBean");
I don't think it is possible to use new operator and ask spring to autowire properties. I think 1 way to solve this is to get a static reference to applicationContext and create a prototype scoped bean.
#Component
public class ApplicationContextLocator {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public ApplicationContextLocator() {
super();
}
#Autowired
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextLocator.applicationContext = applicationContext;
}
}
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
#Component
public class MyObj {
.....
}
public aMethodSomewhereElse(){
MyObj obj = ApplicationContextLocator.getApplicationContext().getBean(MyObj.class)
assertNotNull(obj.getAField());
}