I have a data structure representing a CSV file containing thousands of config settings. The structure is a Java class file with instance variables to represent the records in the file (ie: a HashMap) and the state of the file (errors, warnings, etc).
These classes are not created by Spring as they have state. I would like the class to access system configuration properties which are currently handled by a Spring managed database DAO class. Usually when classes need this DAO I inject it through Spring using #Autowired. But as my data structure is not managed by Spring, how can the CSV structure class access the DAO?
The only method I can think of is when creating the data structure from the Spring managed bean to just pass in the DAO:
CSVDataStruture c = new CSVDataStruture(dao);
See 6.8.1. Using AspectJ to dependency inject domain objects with Spring about using #Configurable
Another way is to get ahold of the application context (in web applications this is WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext)) and get the beans using context.getBean("name"), but it is more of a workaround.
These classes are not created by Spring as they have state.
What makes you think that Spring cannot / should not create objects that have state?
Depending on what you are trying to do (it is hard to figure this out!) I would do one of the following:
Give the CSV class getters and setters for a CVS file parameter and a DAO parameter, and instantiate it using Spring DI. This assumes that the filename is available when Spring wiring occurs.
Create a factory class with a method that instantiates a CSV object from a file parameter. The factory class should have a getter/setter for the DAO object and be instantiated using Spring DI.
Related
Which is the best approach to implement several different databases in one project, using Spring JdbcDaoSupport?
I have several DB with different datasources and syntax: MySQL & Postgres, for example. In pure java-jdbc projects i used Factory Method and Abstract Factory patterns, and multiple DAOimpl classes (one for each DB) with common DAO interfaces for switch between databases. Now i use Spring-jdbc and want to implement similar behavior.
I faced the same matter two year ago and I finally choose an implementation based on a "Spring Custom Scope" (http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-scopes-custom).
The spring frameworks allows multiple instances of the same bean definition to coexists together. They differ only from some contextual settings.
For instance, this bean definition will create various loginAction bean depending on the currently processed HTTP request
<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>
If you create a custom scope called "domain", you will be able to instanciate several datasource based on the same bean definition.
A datasource bean definition based on JndiObjectFactoryBean would let the servlet container manage the database connection (through the web.xml file). However, you would have to variabilize your datasource name with a Spring Property.
Beans like the database Transaction Manager must also be marked with this scope.
Next you need to activate the scope each time an HTTP request is running: I can suggest you to define the datasource name as a prefix of the request url.
Because most of web frameworks allows you to intercept HTTP requests, you can retrieve the expected datasource before processing the request.
Then, create (or reuse) a set of beans specific to the selected datasource and store it inside a ThreadLocal variable (that your custom scope implementation will rely on)
This implementation should look a little complex at first glance, but its usage appears transparent.
I am new to Spring and have a project where I am trying to inject something like the following beans:
ProductHandle selectedProduct
List<ProductHandle > allProducts
When I try to have a List<ProductHandle> autowired into another class, it injects a List containing selectedProduct, rather than the list I actually want. This is even though the name of the autowired property is called allProducts, so I thought this would identify the correct bean.
How would I go about achieving what I want?
--
Edited to show that it isn't just a case with Strings - this is a more generic and hopefully less offensive case..
--
Note beans are being registered as so, since the values are being parsed from command line args.
mySelectedProduct is a ProductHandle
allMyProducts is a List<ProductHandle>
try (final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext()) {
ctx.registerBeanDefinition("selectedProducts", BeanDefinitionBuilder
.rootBeanDefinition(ProductHandle.class, "create")
.addConstructorArgValue(mySelectedProduct)
.getBeanDefinition());
ctx.registerBeanDefinition("allProducts", BeanDefinitionBuilder
.rootBeanDefinition(Lists.class, "asList")
.addConstructorArgValue(allMyProducts)
.getBeanDefinition());
ctx.refresh();
final MyApp app = ctx.getBean(MyApp.class);
app.run();
}
Using standard data structures as Spring beans is an antipattern, don't do it. (Read here about "stringly typed" software)
Either inject the list as a #Value, or wrap it in a custom object that expresses the intent.
Regarding your updated question:
If you have a bean of type X, and register a dependency of type List<X>, Spring will inject a list of all dependencies of the supplied type.
While this is a very handy feature, it's also one more reason never to define standard data structures (like Lists) as Spring Bean. Wrap your list in a custom object and you should be fine.
Also: ProductHandle sounds like it's a business object. Usually, you should not let Spring manage these, but rather the services that act on business objects. Typically, Spring would know about a ProductRepository, or a ProductService, but not a Product or ProductHandle.
The web layer is a notable exception to this rule, but even there, business objects should be method parameters, not Spring beans.
I know I can not use #Autowired annotation in a non managed spring class. But I notice I do able to get a bean instance inside a non managed spring class if I am retrieving it through ApplicationContext getBean method.
can someone explain me why is that ? what is the different between the options ? in both spring doesn't know the non managed class
1) You can use #Autowired in a non-managed spring class if you use #Configurable -with the usage of internal aspect weaving spring will manage to autowired the referenced beans into your "Configurable" class when it is constructed with the "new" operator. Here is an article how this works: http://www.javacodegeeks.com/2013/09/spring-configurable-magic.html
If a class is not configurable spring cannot notice when a new instance is created to autowire its references.
2) The ApplicationContext is "Central interface to provide configuration for an application." Here you have access to the whole spring managed beans etc. That's why you can get everything due to accessing it via ApplicationContext. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html
ok, so here's the major points:
the "bean declaration" (either in xml or java) is just a recipe of how to instantiate the object (not a object itself).
when spring application boots, the beanFactory receives this recipes from beanDefinitionReader, instantiates objects according to them (recipes) and then pass them (objects) to a list of beanPostProcessors (several times) that are "injecting" dependences to the instantiated objects and then puts the objects into hashMap.
roughly saying applicationContext is a class exposing access to this beans;
and that's how you can access this beans out of spring application using applicationContext.
another thing is that, actually you can inject beans into non managed beans through #Configurable. in this case the AspectJ would be used for making this work
I have a java file "DatabaseMan.java" that helps connect to a database and connects helper functions. How can I make it such that it is created once for the life of my spring application, and I can call of its methods "getAllRows" for example, in each of my other resource classes?
Should I be declaring a bean in my Application.java or using some sort of annotation on my "DatabaseMan" class to indicate that it is "injectable"/"resusable"?
I see the following Spring3 example:
http://www.mkyong.com/spring3/spring-3-javaconfig-example/
The issue is, do I have to include this within every single resource:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
HelloWorld obj = (HelloWorld) context.getBean("helloBean");
obj.printHelloWorld("Spring3 Java Config");
Is there a better way to get to the "HelloWorld" with less code and more annotation in Spring 4?
Remember, the ApplicationContext is a container to manage all your beans and their inter-dependencies. It is the entry point to your application. Once you've set it up, all the managed objects are linked up and ready to go.
Is there a better way to get to the "HelloWorld" with less code and more annotation in Spring 4?
It depends where you want to get it. If you want to get it from outside the ApplicationContext, then you need to do what you did. If you want to get into another bean, just inject it and the ApplicationContext will do the rest.
#Component
class SomeOtherBean {
#Autowired
private HelloWorld helloWorldBean;
// do something with it
}
I wrote a custom Struts RequsetProcessor for my application that is manually fetching some references from Spring. It is working just fine, but I would like to do the "right" thing and inject everything I need at construction time.
Is there a way to define a custom Struts RequestProcessor in a way that I can inject Spring objects into it when Struts instantiates this RequestProcessor?
The short answer is "NO". The long answer is "kind of":
Assuming Struts is integrated with Spring in your application via ContextLoaderPlugin, you can do one of two things:
A) Create a "ProcessorContext" bean (or whatever you want to call it) that you would define in your Spring context and access from your custom request processor by obtaining it from Spring's context (which you can get via WebApplicationContextUtils.getWebApplicationContext(getServletContext())).
B) If your custom processor extends Spring's DelegatingRequestProcessor or DelegatingTilesRequestProcessor you can instead write a new request processor that would do what you want functionality-wise, bind it to Spring context with all your dependencies and then extend DelegatingRequestProcessor or DelegatingTilesRequestProcessor to get it from context (either via type or id) and delegate to it. This is essentially an extension of (A) but it delegates all Spring's plumbing to Spring's request processor extension leaving your custom processor Spring-independent.
Spring / Struts integration is described in detail here.