Avoid applicationContext.xml in my Action and Service Classes - spring

I am writing a web application using Struts, Spring framework.
In the Struts Action I am Injecting Service Classes as follows
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
loginService = (LoginService)context.getBean("loginService");
How can I avoid mentioning applicationContext.xml in my Action classes I just have to use
loginService = (LoginService)context.getBean("loginService"); without specifying the .xml file in my class.
I came across to use below while googling
private LoginService loginService = (LoginService)ApplicationContextProvider.getContext().getBean("loginService");
But I do not want to use static method getContext().

Spring support Struts integration in the package org.springframework.web.struts.
Take a look at this article for an example.

Related

Spring (Security) dependency injection

I asked a question more specific to my case about 2 hours ago, but I realised I'm not really addressing my problem at the root cause.
I have a Spring application that uses Spring Security. Throughout my application, (Controllers, service classes etc) I'm using dependency injection and it all works fine. However, I recently started configuring Spring Security, and I can't inject any dependencies inside the classes in my "security" package. Online I read somewhere: "Also when you use #Autowired in the class of which you created a new instance, the Spring context will not be known to it and thus most likely this will also fail" and I was wondering if this maybe had something to do with my issue. My spring configuration basically has one "starting-point", that is the following class:
#Component
#Service
public class AppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext sc) throws ServletException {
AnnotationConfigWebApplicationContext root = new AnnotationConfigWebApplicationContext();
root.register(SecSecurityConfig.class);
sc.addListener(new ContextLoaderListener(root));
sc.addFilter("securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*");
}
}
This code is run on startup. As you can see, it is registering the SecSecurityConfig.class which is where I configure Spring Security. Inside of that class and onwards (all classes it uses and all classes that those classes use) I can't inject any dependencies. I was wondering if anyone could tell me what the problem could be. Sorry if I'm unclear or incorrect - please tell me so, I find the concept of DI somewhat hard to grasp. My component-scan in XML is: <context:component-scan base-package="com.qars"/> which is the package that my security package is also in.
Also all my classes are annotated with #Component or #Service

Cucumber and Spring boot integration

I have a microservice application developed using spring boot and used cucumber to test. I have a separate project folder "bdd" where I stored all my features files and the step defns and this project is not deployed in the war file.
I have a requirement where I need to hit the DAO class's methods directly for some testing and I found that from BDD folder, I don't have the access to get the instance of the beans from spring boot.
Found some articles as well on how to integrate the cucumber and the spring boot using the #RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) annotations. however It seems not to be working for me.
Does anyone have experience any such requirements or could anyone suggest me on what should be the correct approach.
Thanks.
Edited :
I am trying to use an instance of a bean which was initialized already as part of the spring container. when I tried to #Autowire or #Inject using:here registry is the bean instance I am trying to use.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#Component
public class AbstractDefs {
#Autowired
private static ConnectionProviderRegistry registry;
dao = new MyDaoClass(registry);
the variable registry is still null.

Spring Framework 5.0.0.Final parent context not getting loaded

I was trying with latest spring 5.0.0.Final with my EAR project which has a parent context defined in web.xml using context-param
with param names locatorFactorySelector and parentContextKey but spring could not able to load the parent context. When i checked the ContextLoaderListener source code it seems like there is no logic applied to pick parent context. Here my question is does spring 5 provide any default implementation of ContextLoader which caters loading of parent context or spring 5 dropped, if not what is the approach to support this, do i have to implement our own ?
The loading of the parent context based on locatorFactorySelector were handled at ContextLoader#loadParentContext(). But they changed it to return null in this commit.
As said by the javadoc , I think you can create a new ContextLoaderListener and override this method to return the parent context:
public class FooContextLoaderListener extends ContextLoaderListener{
#Override
protected ApplicationContext loadParentContext(ServletContext servletContext) {
//load and return the parent context ......
}
}
Then use this ContextLoaderListener to start up Spring :
<listener>
<listener-class>org.foo.bar.FooContextLoaderListener</listener-class>
</listener>
For me this below piece of code worked fine.
public class BeanFactoryContextLoaderListener extends ContextLoaderListener {
private static Logger log = Logger.getLogger(BeanFactoryContextLoaderListener.class);
#Override
protected ApplicationContext loadParentContext(ServletContext servletContext) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beanRefFactory.xml");
return ctx;
}
}
Obviously I added a listener too in web.xml.
My team recently bumped into the same problem. We wanted to start using Webflux and it requires Spring 5.
Here is what I did:
Manually reintroduce BeanFactoryLocator mechanism. Take following classes from Spring 4, put it into your code and fix packages:
AbstractUrlMethodNameResolver
AnnotationMethodHandlerAdapter
BeanFactoryLocator
BeanFactoryReference
BootstrapException
ContextSingletonBeanFactoryLocator
DefaultAnnotationHandlerMapping
HandlerMethodInvocationException
HandlerMethodInvoker
HandlerMethodResolver
InternalPathMethodNameResolver
MethodNameResolver
NoSuchRequestHandlingMethodException
ServletAnnotationMappingUtils
SingletonBeanFactoryLocator
SourceHttpMessageConverter
WebUtils
XmlAwareFormHttpMessageConverter
Following Subhranil's advice from this thread, use custom ContextLoaderListener which loads parent context same as in Spring 4. Then use it in web.xml.
In each WAR's spring-servlet.xml add DefaultAnnotationHandlerMapping so it scans for controllers. Accompanying beans like AnnotationMethodHandlerAdapter are also needed.
It worked for us.
If all you need is your context-param in any of your spring managed class you are looking for ServletContextAware.
Just implement that class and override its method to get the ServletContext object. Later you can also get the context-params using the ServletContext object.
Check out a very similar question.
Apparently, the mechanism for locating the parent context was removed with SPR-15154 (see also the corresponding Github issue spring-framework#19720).
One workaround is to extend org.springframework.web.context.ContextLoaderListener and re-implement the loadParentContext method is described in this stackoverflow answer.
There is probably a better way to solve parent context loading in Spring 5.x, which I still have to figure out.

Integrating Spring XML beans from external jar into a CDI application

I have a new CDI Java EE application running on WebSphere. Now I want to use an existing module (.jar) in my CDI project, however the existing module uses Spring with Spring annotations and an Spring XML configuration file with additional bean definitions in it. Normally I would just import the Spring XML in my project, but in the CDI application this will not work.
I tried to load the Spring XML using JBoss Seam, like so:
#Produces
#SpringContext
#Configuration(locations = "classpath*:external-spring--context.xml")
ApplicationContext context;
But the context is null? I cannot realy find good examples on how to do this, help is much appreciated :)
I solved it by adding an CDI producer that will create the Spring context using the spring XML file:
public class SpringBeansFactory {
#Inject
ApplicationContext context;
#Produces
public BusinesService getBusinessService() {
return context.getBean(BusinesService.class);
}
}
class SpringContextFactory {
#Produces
public ApplicationContext getApplicationContext() {
return new ClassPathXmlApplicationContext("classpath:spring-context.xml");
}
}

Migrating to DAOs and Spring from Servlets and JDBC, advice?

We've got webapps with servlets that make JDBC calls directly. We've mostly replaced the JDBC calls with Spring JDBC which has been a vast improvement (no more leaked connections!).
I'd like to go a little farther with this mess of code and use DAOs. I'm not sure how to do this with the servlets in the mix, however, because I know the servlets can't be #autowired.
As an example, right now I've got an interface:
public interface AdminDao
{
public boolean isAdmin(int id);
}
and an implementation
package myapp.dao.impl;
#Repository
public class AdminDaoSpring extends SimpleJdbcDaoSupport implements AdminDao
{
private static final String _isAdminSql
= "SELECT count(*) from admin WHERE id=?";
public boolean isAdmin(int id);
{
int cnt = getSimpleJdbcTemplate().queryForInt(_isAdminSql, id);
return (cnt > 0);
}
}
In my applicationContext.xml I have
<bean id="adminDao" class="myapp.dao.impl.AdminDaoSpring"></bean>
I've got a servlet, AdminCheckServlet, that currently makes the above query. How do I change this to use an adminDao instance? I can't annotate the servlet with #Service because the DAO won't get injected as the servlet is constructed by the container (Tomcat) and not Spring.
Should I make another class, AdminService, and have that handle all the calls using AdminDao? The servlets affecting the Admin table would all then instantiate AdminService and use that instead of direct JDBC calls. That doesn't feel right, however.
Thanks!
Paul
I would look into SpringMVC, and use a Spring Controller instead of using java servlets directrly.
Spring MVC
It is pretty easy to use. You create a simple web.xml deployment descriptor to have your endpoints call Springs DispatcherServlet. With this done, you can create a controller class to map these endpoints to methods in the controller. Your controller can be defined as a part of your applicationContext, and can therefore have its DAO (or other services) injected.
You need to use a MVC Framework (the most popular are Struts 1.x, Struts 2 and Spring MVC), and you will be able to call you daos from your controllers (which are called "Actions" in Struts frameworks).
Here is a valuable resource about this : http://www.ibm.com/developerworks/java/library/j-sr2/index.html
I'm not sure you need services, if you don't have much reusable business logic.

Resources