I'm making a web app using spring, in web.xml I have defined context-param to look for application-context.xml file which scans for everything besides controllers and app-servlet.xml that scans only for controllers.
application-context.xml contains the datasource to the database and I inject the datasource in the daos like this:
#Autowired
DataSource dataSource;
Now if I try create a DAO by hand in the controller(I know i probably should use services for that, but it's just for test purposes for now) I get null pointer exception, however when I inject the DAO it loads properly.
So why does it happen? DAOs are not managed by the DI container only the datasource is, so why can't I create the dao by hand?
Spring bean factory and "new" are orthogonal: once you call "new", it's in your hands, not Spring's.
The situation you describe is common: You want Spring to manage bean lifecycle and dependencies in production, but when testing you want to do it yourself with mocks. My suggestion is to write your app to use Spring for DI and bean creation, but have constructors for manual injection of mocks when you test.
Yes; objects not under Spring's control are... well, outside of Spring's control.
There are some ways around this, e.g., allowing newed objects to get Spring DI (e.g., byte code manipulation).
Related
Using Spring Boot 1.5.12, we create scoped proxies for #ConfigurationProperties beans. We do this so that we can effectively have property values that are scoped to the user/session/etc. We use a BeanFactoryPostProcessor to register a scoped proxy created by ScopedProxyUtils.createScopedProxy and change the scope of the target bean definition to our custom scope.
This worked great in Spring Boot 1.5.12. However, in Spring Boot 2, the introduction of the Binder API has made this stop working. This is because when Spring Boot binds #ConfigurationProperties in its ConfigurationPropertiesBindingPostProcessor, it uses Bindable.of(type).withExistingValue(bean) passing in a type (e.g. org.example.Foo) and the bean which is an instance of ScopedProxyFactoryBean. Bindable checks that bean is an instance of type which it's not and things blow up.
Does anyone know of a general way to accomplish this? Specifically, to replace the #ConfigurationProperties bean definition with a proxy while still allowing the properties to bind to the instance? I've considered delaying the creation of the proxy until after the target has already been bound by ConfigurationPropertiesBindingPostProcessor (i.e. in my own BeanPostProcessor). However, at this point the bean is instantiated and my proxy can only replace the bean. It can't really leave the original bean in the context as a target. So I'm struggling with how to do this using a BeanPostProcessor.
EDIT: I've created a simple example project that demonstrates the issue (with the ability to check out code that works on Spring Boot 1 and fails on Spring Boot 2).
I have a spring webapp with annotation driven configuration.
All Controllers, Repositories are autowired.
When integrating Spring Security I defined a separate security-app.xml. I created a Service called LoginUserService which implements UserDetailsService. Now the method loadUserByUsername() method of this class gets invoked for authentication.
This class has an autowired dependency for UserRepository. Now this autowired dependency turns out to be null. To fix this I enable annotation driven configuration and add the package name for the repository class in component scan configuration.
This solution is also discussed here
spring security with custom user details
But now the problem is that the UserRepository has an EntityManager field with #PersistenceContext annotation. For the spring security configuration it is able to locate the UserRepository but not able to locate the entity manager. Should I create a new EntityManagerFactory here? I guess that will create two persistence units in my application?
How can I inject an autowired dependency to UserRepository created with the original servlet xml?
Update
This is briefly discussed here:
https://stackoverflow.com/a/7078395/161628
But I guess a canonical detailed answer will be more useful to me.
Update
How about using ApplicationContext to get the UserRepository at runtime?
if (userRepository == null) {
userRepository = ApplicationContextProvider.getApplicatonContext().getBean(UserRepository.class);
}
Why is Spring's ApplicationContext.getBean considered bad?
EDIT: Beans that you declare in your config for your DispatcherServlet are not going to be available to any beans you declare or component scan in your contextConfigLocation config files. So in this case, if you're setting up your JPA config in your config file that you load for your DispatcherServlet there is no way to wire that in to beans your declare in your security config. You need to move any "core" bean config like that (datasource config, db connection pool config, JPA/Hibernate config, repository/service component scanning, etc.) into a config file that you load via the contextConfigLocation. Then that stuff will be available both to your security beans and your MVC beans. I think generally the idea is to only load MVC specific beans in your DispatcherServlet config (e.g. Controllers, views, request handlers, request scoped beans, etc.). That way you ensure you have a clean separation between MVC code and non-MVC code, with only a one-way dependency from the MVC code to the "core" code, and no dependencies on MVC code in your "core" code. This helps make your code more modular, and makes it easier to reuse your "core" code in other ways, specifically in unit tests.
(Original comment text was asking about how the security config is loaded, if it's in the contextConfigLocation or somewhere else.)
I am new to Spring and the bean concept, so sorry if asking the obviously.
I have set up a Java project and used the Hibernate framework to make my connections to the DB (using hibernate tool on eclipse, really recommended btw).
My basic setup was as follows:
some hibernate pojos (generated by Hibernate tools),
hibernate mapping files (hbm.xml files).
The configuration was set in hibernate.cfg.xml file placed at my root of the packages.
I initially setup a HibernateUtils class that gets a session from my sessionFactory.
some classes that act as Dao - creates the queries using the pojos and the hibernateUtils to get the session.
This was working fine with hibernate's powerful framework. Then I migrated to project to Spring MVC. From the various tutorials I read I understood that some changes need to be done in order to make things play nicely again. The main change is that the Spring FW now loads the beans by itself, therefore the following:
the pojos did not change, nor did the hbm.xml files
The configuration is no longer set at hibernate.cfg.xml - the Spring MVC FW loads it's own LocalSessionFactoryBean once I declared it in the XML files (Spring search for xmls as part of the initialization process). So I created a separate xml file called spring-hibernate.xml, that has the DB definition, the session factory bean and a hibernate template. To complete it, the xml file also declare the location of the Dao and the hbm files.
with hibernate template configured in the xml, there is a bean injection, therefore I changed the Dao files to add getter/setter to a hibernate template property. Then using this - the Dao class may create the db query.
All of this configuration works fine and I can get the Spring FW initialize the Dao classes (I put a sysout just to confirm that the Dao classes are injected with the hibernate template during MVC startup). Now my problem is - how to get access to the Dao bean instance created?
In my logic part, I get a hold of the bean as follows:
ClassPathXmlApplicationContext appContex = new ClassPathXmlApplicationContext(new String[] {"spring-hibernate.xml"});
UserUIDDao userUIDDao= (UserUIDDao)appContext.getBean("UserUIDDao");
Problem is - this is a NEW reference to a newly created bean and not the same one created during the spring MVC startup.
So my questions are: how to get a hold of the original bean created by the Spring init process? and - is my setup correct?
the pojos did not change, nor did the hbm.xml files
That's correct.
The configuration is no longer set at hibernate.cfg.xml - the Spring MVC FW loads it's own LocalSessionFactoryBean once I declared it in the XML files (Spring search for xmls as part of the initialization process).
You can choose to use Spring to configure Hibernate (but you could keep your hibernate.cfg.xml).
So I created a separate xml file called spring-hibernate.xml, that has the DB definition, the session factory bean and a hibernate template. To complete it, the xml file also declare the location of the Dao and the hbm files. with hibernate template configured in the xml, there is a bean injection, therefore I changed the Dao files to add getter/setter to a hibernate template property. Then using this - the Dao class may create the db query.
Using Spring's HibernateTemplate is one option, but you could also go template-less and just inject Hibernate's SessionFactory and use sessionFactory.getCurrentSession().
This is actually the officially recommended approach for new projects, check out So should you still use Spring's HibernateTemplate and/or JpaTemplate?? and the javadoc of HibernateTemplate.
Now my problem is - how to get access to the Dao bean instance created?
You inject it where needed (typically, in your services).
In my logic part, I get a hold of the bean as follows (...)
No, don't do this. This "service locator approach" actually defeats the point of a DI container like Spring. Configure Spring to inject your DAOs where needed.
I need to inject a Spring bean into a Seam context. Unless I declare the spring bean as a EJB, I cannot get it injected into other seam-managed components. But when I do this, all the spring injected fields are usless cause Seam creates new instances at run-time.
I also tried to add the <seam:component/> element to the spring bean definition and tried to inject it in the container with the #In("beanId") annotation in the target class but I always end up with a NullpointerException...
EDIT:
I read the online articles and did as they say. My spring component is also added to the seam context (I can tell, cause when I define one with the same ID in seam, it complains). Looks like #In is not picking up....
Have you read this chapter? It should tell you exactly what to do.
Raoul,
Although i do not use Seam along with Spring, chapter 15 of Seam In Action books talks about Spring integration. It is free and is updated.
You have said
I also tried to add the element to the spring bean definition and tried to inject it in the container with the #In("beanId")
Seam in Action book says
The EL expression used in the #In annotation, #{tournamentManager}, resolves to an equivalently named bean in the Spring container, courtesy of the delegating variable resolver
Do you have to use #In("#{beanId}") instead of #In("beanId"), do not ?
I have seen
By default, <seam:component/> will create a STATELESS Seam component with class and name provided in the bean definition.
<bean id="someSpringBean" class="SomeSpringBeanClass" scope="prototype">
<seam:component/>
</bean>
And
The scope attribute of <seam:component/> may be used if you wish the Spring bean to be
managed in a particular Seam scope. The Spring bean must be scoped to prototype if the
Seam scope specified is anything other than STATELESS.
Have you done as above ?
I have a project using Seam + Spring and I have to set #In(create=true) when I want to inject a Spring bean into my Seam component otherwise I get a NullPointerException, you should try it.
I got the same problem as yours. I followed strictly the "Chapter 27. Spring Framework integration" in seam ref. document. But my spring bean was never got injected to seam component. And finally, I found out I had the #BypassInterceptors in my seam component. By removing that annotation, my spring bean was successfully injected. Then I realized that, dependency injection is handled by seam BijectionInterceptor. Thus, the #BypassInterceptors will effectively bypass this filter :)
What role is Spring taking in Struts + Spring + Hibernate?
Spring provides many different "modules" and different programmers will use different parts of Spring.
However, commonly in this sort of stack, you will see Spring being used as a provider of
An inversion of control container for dependency injection
An abstraction to Hibernate called "HibernateTemplate"
Framework classes for simplifying Aspect Oriented Programming
Transaction support, often "declaratively" via the IoC container and AOP.
Well, Hibernate handles the persistence part, JSP handles your GUI, Struts controls the flow between pages/actions/etc, and Spring can manage all your beans which contain the main business logic, instead of using EJB. Plus it can simplify the coding of your Hibernate DAO's and transaction managing.
Instead of having to code your Locator to obtain some EJB through JNDI and all that stuff, you can just get the Spring ApplicationContext and ask for the bean you need. All the beans defined in Spring can be interconnected. If you have to connect one of your beans to an external EJB through JNDI you can even do so without any code (Spring offers a JNDI proxy object which obtains the reference you give it and returns it as an object with the interface you specify). This can help you simplify unit testing of all those beans and change the config without recoding anything; you can use one of Spring's PlatformTransactionManagers to manage a DataSource or point it to a J2EE container's JTA manager; define your own pooled DataSource or use your container's DataSource published through JNDI, etc.
Well to add;
(Views and Controllers) Struts for its extensive JSP features with Struts tags and web request handling features
(Service and application management) Spring to handle the ORM and service layers with its excellent dependency injections,etc.
(ORM with db independence) Hibernate for well proven ORM