spring populating ServletActionContext? - spring

We use Spring IoC and Struts as the web app framework. There is a helper class in the presentation layer which reads some stuff from request and populates some data as request attributes for the action and other classes to use. So we need the request object (HttpServletRequest) in this class, and we use ServletActionContext.getRequest() for this.
The helper class is a Spring bean in request scope, and gets invoked for all requests. The data loading happens in a method which is configured as "init-method" in the helper's Spring bean. The actions are also Spring beans.
In struts.xml, we refer to the action beans configured in spring by name. For eg:
<action name="myAction" class="actionBeanNameFromSpring">
<result>myResult.jsp</result>
</action>
In this case, the ServletActionContext.getRequest() method in the helper returns the proper request object. However, we have other actions in the XML where we directly refer to the action class instead of action bean i.e. we bypass Spring. In these cases, the request comes out as null.
Now I know that the solution to this is to change all action entries in XML to refer to Spring beans. But I would like to know why exactly this happens. AFAIK, ServletActionContext is a Struts thing and is handled completely by Struts. How does going through Spring (i.e. using Spring action beans) populate the context, and not going through Spring (i.e. using Action class name) doesn't?
#Roman
I am assuming the entire content is unnecessary. Given below is the relevant part:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
....
<!-- the helper which accesses request -->
<bean id="myActionHelper" class="com.company.product.webapp.package.MyActionHelper" init-method="init" scope="request">
<property name="someSvcBean" ref="someSvcBean" />
</bean>
....
<!-- a typical action -->
<bean id="myAction" class="com.company.product.webapp.action.MyAction" scope="request">
</bean>
....
</beans>

Related

Where is hided <context:annotation-config/> in spring boot?

To work via annotations in Spring need to define:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
xmlns:context="http://www.springframework.org/schema/context">
<context:annotation-config/>
</beans>
at
annotation-config.xml
But I created a simplest Spring boot Application (lets say I select lust Web in initialazr)
It works on annotations but there isn't any annotation-config.xml there and nor mentioning of ,
where is hidden?
You only need to add <context:annotation-config /> or <context:component-scan /> (which implies annotation driven config) when using an ApplicationContext implementation that doesn't support annotations out-of-the-box.
When only using XML based configuration you also use one of the XML enabled ApplicationContext implementations, generally that would be XmlWebApplicationContext. With these you would need to instruct the ApplicationContext to enable annotation processing.
When using Java based configuration you generally use an annotation based ApplicationContext, default would be AnnotationConfigWebApplicationContext. Due to its nature of processing Java configuration classes it has annotation processing enabled by default.
Spring Boot uses the latter (it actually uses a specialized subclass for this). Hence you don't need to explicitly enable it.

Spring managed Transaction commits where it shouldn't

in "applicationContext-base.xml" I add below:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
>
.....
<!-- transaction support-->
<!-- PlatformTransactionMnager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- enable transaction annotation support -->
<tx:annotation-driven transaction-manager="txManager" />
and I want to setup a transaction to a function in the "controller"
#Controller
#RequestMapping("/ywdata")
public class YwController extends BaseController{
....
#Transactional(timeout=1)
private void submitNewSXSQ(Map map, HttpServletRequest request, HttpServletResponse response) throws Exception {
...//STEP1 :do some db insert and update STEP1
if(true)
throw new Exception("test transaction ");
...//STEP2: do another db insert and update
and I expected the db operation should never be commit since I throw a exception before return. but actually not.
There are multiple issues with your code:
#Transactional on private methods don't work
#Transactional on #Controller annotated classes usually don't work
rollback is not performed for checked exceptions
The last issue can be easily understood. Let me explain the first two problems. AOP in Spring works like this:
before the application context is initialized, Spring searches for beans which require method interception
a special proxy bean is registered for each of these beans... the proxy is either dynamic interface implementation (JDK proxy) or a dynamic subclass (CGLIB proxy) of your target bean
the proxy replaces the definition of your bean... original definition is renamed and marked as not eligible for autowiring (but it is still present on application context)
the methods on proxy are very dumb - all they do is interception logic (i.e. calling some aspect before/after/around execution) and calling the original proxied target bean method
Why private methods are problem:
with JDK proxying (default):
#Transactional won't work if you have #Transactional on non-interface method (only interface methods are present on the proxy)
with CGLIB proxying:
##Transactional won't work if you have #Transactional on private or final method (only non-private and non-final methods can be overridden in dynamic subclass)
And why controllers are problem:
Spring's RequestMappingHandlerMapping (bean responsible for mapping requests to your #Controllers) asks application context to get all beans with #Controller annotation
this might return your original class, not the proxy (I think there was a bug for this in Spring JIRA, so it might be already fixed)
in case of JDK proxying, you need to add the annotation to the interface (so that the proxy is annotated)... this means that you would need to define interfaces for your controllers
What to do:
I suggest you to move transaction handling to service level
If you want your transaction to be wrapped around the whole request, you might take your inspiration from OpenSessionInViewFilter.
Also I encourage you to put breakpoint in your code and check the stack trace and look for the AOP proxy.
If you still want to manually handle transactions in some random part of code, you can use TransactionTemplate helper class.
From Spring documentation, it is the default behavior: Transactions are marked for rollback only for unchecked exceptions.
See section 10.5.3 of doc

Spring claiming that identical classnames are different

I'm making my first forays into spring and am getting the following error trying to run on eclipse:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'model' must be of type [com.myCompany.project.Model], but was actually of type [com.myCompany.project.Model]
Code causing the exception:
import com.myCompany.project.Model;
// some code
public Model getModel() {
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("client-context.xml");
return applicationContext.getBean("model", Model.class);
}
Spring xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<bean id="model" class="com.myCompany.project.Model" />
</beans>
The client-context.xml is located in project/resources, the code in project/src/main/
I assume this is a classpath issue, but I am at a loss as to what to do to fix it.
Java and Spring are case sensitive. This:
<bean id="model" class="com.myCompany.project.model" />
is not the same as this:
<bean id="model" class="com.myCompany.project.Model" />
I'd think about some better names. Those aren't very insightful.
I don't like the way you're going about this. You shouldn't have a bean that has to access the app context this way. You'll have to post more code to be sure, but you ought to be wiring that model bean into object that wants it, not doing what you're doing.
The only reason for doing what you're proposing is if the bean interacting with the app context is creating using new rather than the Spring bean factory. Since you're just starting with Spring, I would recommend letting Spring handle all dependencies.

Spring MVC 2.5 Using a mix of annotations & XML configuration but xml gets ignored

In my Spring MVC webapplication I want to mix xml based configuration with annotations:
I use annotations like #Controller, #RequestMapping("bla.htm"), #RequestParam etc. to resolve HttpRequests to Controller Methods. Therefore I added
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<context:component-scan base-package="somePackage.controller"/>
to my dispatcher-servlet.xml.
But my controllers have attributes. Those attributes could be injected via #AutoWired annotation. But I also have do define Scopes. So i would have two annotations per attribute, which makes the code bad readable. So I want to inject dependencies in my applicationContext.xml file.
Is there a way I can keep the annotation-driven request-mapping but use context.xml files for Dependency Injection? Or is it only possible to use EITHER annotations OR xml configuration?
note: my beans for dependency injection are in a different xml file.
PS:
I should have mentioned, I use Spring 2.5 and can't upgrade it.
No, <mvc:annotation-driven> works fine with XML. But you'll need to get rid of the <context:component-scan>.
Update: with Spring 2.5, this should get you started:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<!-- now add some controllers -->
</beans>
Yes this is certainly possible.
To use the controller annotations such as #Controller and #RequestMapping make sure you put
<mvc:annotation-driven/>
in your <servletname>-servlet.xml
Then simple define your controllers using the normal XML bean notation such as:
<bean class="com.company.controllers.AController">
<property name="propertyName" ref="beanId" />
</bean>
These bean refs can come from any other applicationContext.xml defined in your web.xml too.

Why does my Spring AOP aspect work in my unit test but not my webapp?

I have an aspect working correctly in my unit tests, a log message is printed from the actual method, and afterwards from the aspect applied.
When running my webapp though, I only see the result of the '#afterReturning' advice applied, my method does not execute first.
My config:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean id="loggingAspect" class="com.mypackage.MyAspect" />
</beans>
Any ideas ?
Thanks for your help.
Information you provided in not enough to analyze. So check below things in your web app,
1) Verify that the method you are expecting to be intercepted by your advice, belongs to spring bean class & not some other servlet or other class defined outside spring. If any class is not initialized through spring then aop advice can not be applied to that class.
2) Verify that above aop & advice configs are put in proper context xml for spring. Like in case of spring-mvc, you have to explicitely define the name of your application context xml. And in that application context xml only you have to write aop configurations.
3) Verify if your pointcut is appropriate to find exact class & method for advice.
See if these things are in place.

Resources