Manual configuration equivalent to mvc:annotation-driven [duplicate] - java

This question already has answers here:
Howto get rid of <mvc:annotation-driven />?
(4 answers)
Closed 9 years ago.
What exactly would be an equivalent manual configuration to mvc:annotation-driven in spring mvc? Because my webapp implements RequestMappingHandlerMapping, I cannot use mvc:annotation-driven but have to configure this myself.
Specifically I'm wondering what configuration has to be included in order for the #Async annotation to work. I am not sure if it does atm. I'm starting a background task at startup which is supposed to run as long as the webapp is running and it seems to me that the whole server waits for this (never-ending) method to finish. The #Async-Method is in a worker-service which gets called by another service on #PostConstruct.
Here are the two classes:
#Service
public class ModuleDirectoryWatcher{
#Autowired
ModuleDirectoryWatcherWorker worker;
#PostConstruct
public void startWatching() {
worker.startWatching();
}
}
#Service
public class ModuleDirectoryWatcherWorker {
#Async
public void startWatching() {
createPluginDir();
initializeClassloader();
initializeWatcher();
watch();
}
}
The relevant part of my applicationContext.xml looks like this so far:
<bean name="handlerAdapter"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"</bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
<bean name="handlerMapping"
class="com.coderunner.caliope.module.api.impl.ModuleHandlerMapping">
</bean>

Now I feel silly... In order to work, #Async and #Scheduled need
<task:annotation-driven executor="myExecutor" scheduler="myScheduler" />
<task:executor id="myExecutor" pool-size="5" />
<task:scheduler id="myScheduler" pool-size="10" />
even if you don't use
Maybe it helps someone out there

Related

How do I actually use a Spring pooled object?

I am working through an example of spring pooling described here.
http://docs.spring.io/spring/docs/2.0.0/reference/aop-api.html#aop-ts-pool
I have read through a very similar question here, but still don't have an answer.
How to use Pooled Spring beans instead of Singleton ones?
Assuming I have the following beans defined in my SpringConfig file, how do I actually use the pooled objects?
<bean id="businessObjectTarget" class="com.mycompany.MyBusinessObject" scope="prototype">
... properties omitted
</bean>
<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName" value="businessObjectTarget"/>
<property name="maxSize" value="25"/>
</bean>
<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="poolTargetSource"/>
</bean>
I am doing something like this but I have no idea how to tell if it working.
#Resource(name = "businessObject")
private MyBusinessObject businessObject;
...
method() {
...
businessObject.method();
...
}
How am I actually supposed to use the pooled object?
Thanks.
PS - I am even less sure of it working now. I made the following change and submitted two threads. The first one worked, the second one got an error indicative of simultaneous use:
<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName" value="businessObjectTarget" />
<property name="maxSize" value="1" />
<property name="whenExhaustedActionName" value="WHEN_EXHAUSTED_FAIL" />
</bean>
I am very skeptical.

Spring's nested transactions with different transactionManagers

I'm new to Spring's transaction management having troubles to tackle the following scenario of nested transactions while integrating Spring (3.2) and Hibernate (3.6).
I've declared two appContext files as following.
File1) applicationContext-student.xml
<bean id="studentProjSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
...**dataSource1_on_Machine1**...
</bean>
<bean id="studentProjTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="studentProjSessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="studentProjTransactionManager" />
<bean id="studentDao" class="com.my.univ.employee.dao.studentHibDao" scope="singleton" />
<bean id="studentService" class="com.my.univ.student.service.studentServiceImpl" scope="singleton">
<property name="studentDao" ref="studentDao" />
</bean>
File2) applicationContext-employee.xml
<bean id="employeeProjSessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
........**dataSource2_on_Machine2**...
</bean>
<bean id="employeeProjTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="employeeProjSessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="employeeProjTransactionManager" />
<bean id="employeeDao" class="com.my.univ.employee.dao.EmployeeHibDao" scope="singleton" />
<bean id="employeeService" class="com.my.univ.employee.service.EmployeeServiceImpl" scope="singleton">
<property name="employeeDao" ref="employeeDao" />
</bean>
Imported above two files in the following file.
File3) applicationContext-university.xml
<import resource="applicationContext-student.xml" />
<import resource="applicationContext-employee.xml" />
<bean id="personService" class="com.my.univ.person.service.PersonServiceImpl" scope="singleton">
<property name="studentService" ref="studentService" />
<property name="employeeService" ref="employeeService" />
</bean>
Questions
Let's assume that method level #Transactional annotations are provided with the right txManager names in studentService and employeeService but not in personService.
Q1) If I declare a method in personService as #Transactional, which txManager gets picked?
Q2) How does the nested txManager scenario work if the txManagers in the hierarchy are different from each other?
Ex: If a #Transactional method in personService invokes a #Transactional method in studentService and then another #Transactional method in employeeService (with in the same method of personService).
Q3) How does the commit, rollback elements work in above scenario.
Q4) Readonly operations vs Read/Write operations in above scenario.
It'd be great if anybody could clarify the above.
Thanks.
The #Transactional annotation takes as a value the bean name of the transaction manager. From the documentation:
public abstract String value
A qualifier value for the specified transaction.
May be used to determine the target transaction manager, matching the qualifier value (or the bean name) of a specific PlatformTransactionManager bean definition.
Default:
""
So in your case, explicitly defining:
#Transactional("studentProjTransactionManager")
#Transactional("employeeProjTransactionManager")
should wrap transactionally using the right transaction manager.

Can Controllers specify which Interceptors to use

I'm moving an existing spring (3.1.1) web mvc Controller (called LoginController) to using annotations, I had
<bean id="loginHandlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="licenseInterceptor" />
<ref bean="propertyInterceptor" />
<ref bean="localeChangeInterceptor" />
</list>
</property>
<property name="urlMap">
<map>
<!-- used to include references to my LoginController -->
<entry key="error" value-ref="error" />
</map>
</property>
<property name="order">
<value>1</value>
</property>
</bean>
I changed my LoginController to be annotated. Some other classes had also been annotated previously so it will use the existing...
<bean id="requestMappingHandlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="interceptors">
<list>
<ref bean="licenseInterceptor" />
<ref bean="loginInterceptor" />
<ref bean="propertyInterceptor" />
</list>
</property>
</bean>
LoginController cannot use the loginInterceptor that others use however as it's a pre-login Controller but a post-login Interceptor.
What I want to know, is there a way to tell Spring that this specific Controller should NOT be used with a specific (loginInterceptor) Interceptor? And perhaps if it (and only it) could also use localeChangeInterceptor.
What have I tried
(works in Spring 3.2) Adding <mvc:interceptors> and their namespace to config but they don't seem to allow multiple bean references and exclude-mapping is Spring 3.2, I'm 3.1.1
Doing the processing in LoginInterceptor, handler is not of type LoginController - I can do ((HandlerMethod)handler).getBean() instanceof LoginController and that works but it's not pretty or flexible.
using the spring mvcnamespace you could do the following:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/login"/>
<ref bean="loginInterceptor"/>
</mvc:interceptor>
<!-- .. further interceptors -->
</mvc:interceptors>
this allows to add paths that should not be intercepted by a specific interceptor.
add the mvc namespaces to your configuration root element..
xmlns:mvc="http://www.springframework.org/schema/mvc"
... and the schema ...
xsi:schemaLocation=" .....
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
...."
I've done this in the past by implementing it in the preHandle method in a HandlerInterceptorAdapter.
#Override
public final boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// inspect handler object to see if it's LoginController
}
Here is what it took to get this working in the LoginController. A little like the solution of #blank but with some other nonsence, I'd still like to have a spring (annotation or config) way of fixing this though
public final boolean preHandle(HttpServletRequest request)
{
if (handler instanceof HandlerMethod &&
((HandlerMethod)handler).getBean() instanceof LoginController)
{
return true;
}
...
}

Thread.setDefaultUncaughtExceptionHandler in Spring

I am developing a Spring application, and was wondering if there a part of the framework that let's me do something like this in a more elegant way, such as configuring something in XML?
If the purpose of your question is to set a custom UncaughtExceptionHandler through your application context, you can use:
<bean id="myhandler" class="java.lang.ThreadGroup">
<constructor-arg value="Test"/>
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="java.lang.Thread"/>
<property name="targetMethod" value="setDefaultUncaughtExceptionHandler"/>
<property name="arguments">
<list>
<ref bean="myhandler" />
</list>
</property>
</bean>
(N.B. replace myhandler with an Thread.UncaughtExceptionHandler of choice...)
You can also use #ControllerAdvice annotated classes for uncaught exception handling. Referencing from https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc, the following code will catch any Exception:
#ControllerAdvice
public class MyUncaughtExceptionHandler {
#ExceptionHandler(value = Exception.class)
public void defaultExceptionHandler(Exception e) {
// do whatever you want with the exception
}
}

Using a DAO on a Bean used by a Spring Scheduled Task

I'm developing a web application using Struts2 + Spring, and now I'm trying to add a scheduled task. I'm using Spring's task scheduling to do so. In my applicationContext I have:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
...
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
And then I have my DAO that uses this entityManagerFactory:
<bean id="dao" class="data.GenericDAO" />
So this works flawlessly within the web application. But now I have a problem when creating the scheduled task:
<task:scheduled-tasks scheduler="notifier">
<task:scheduled ref="emailService" method="sendMail" fixed-rate="30000" />
</task:scheduled-tasks>
<task:scheduler id="notifier" pool-size="10" />
<bean id="emailService" class="services.emailService" >
<property name="dao" ref="dao" />
</bean>
This executes the method sendMail on my emailService class every 30 seconds. And my emailService has the DAO injected correctly. The thing is that I can fetch objects with my DAO using the findById named queries, but when I try to access any property mapped by Hibernate, such as related collections or entities, I get an "LazyInitializationException: could not initialize proxy - no Session ". I don't know what's wrong, since I believe the scheduled task is being managed by Spring, so it should have no problem using a Spring managed DAO. I must say that I'm using the openSessionInView filter on my struts actions, so maybe I need something similar for this scheduled task.
Any help or suggestion will be appreciated, thanks!
Edit: Finally I found a way to fix this. I changed my regular Dao with one where I can decide when to start and commit the transaction. So before doing anything I start a transaction and then everything works OK. So I still don't know exactly what causes the problem and if someday I'll be able to use my regular DAO, for the moment I'm staying with this solution.
OpenSessionInView won't help you, because you don't have a web context. You need Spring's Declarative Transaction Management.
In most cases, what you need to do is just this XML:
<!-- JPA, not hibernate -->
<bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="myTxManager" />
<!-- without backing interfaces you probably also need this: -->
<aop:config proxy-target-class="true">
(Annotate your EmailService class as #Transactional to enable this)

Categories