Does Spring WebFlux have analogue of Micronaut ExecuteOn annotation? - spring

Micronaut supports #ExecuteOn annotation that enables you to schedule all the handlers of a controller on IO pool:
#ExecuteOn(TaskExecutors.IO)
#Controller
public class BookController {
#Get("/{id}")
Book get(Long id) {
//This will be a thread on the IO thread pool, so it is OK to block
}
}
Does Spring WebFlux has something to have the same semantics? I know how to use Schedulers.boundedElastic(), but sometimes we have completely blocking controllers that hit old APIs or third party libraries and want to have simpler code there.

Related

Spring integration : does SpringApplicationContext call #ServiceActivator in config?

I am reading Spring integration source code, and I have some questions understanding the workflow:
Does the #SpringBootApplication class, when calling application.run(), will call directly beans annotated using #ServiceActivator ? For example in my config file I have :
#Bean
#ServiceActivator(inputChannel = test)
public MessageHandler myHandler() {
return new SomeHandler();
}
when the application.run() is fired, the method handleRequestMessage() of SomeHandler will be called ? Am I understanding it right ?
Well, you need to understand that there are two parts of this matter:
Configuration phase when Spring parses all the annotations to register beans in the AppplicaitonContext. This way even that #ServiceActivator is consulted and a event-driven endpoint is registered as a bean as well.
Runtime part of Spring Integration environment. Here the mentioned endpoint is subscribed to the inputChannel and when message is has arrived the handleRequestMessage() is triggered from that SomeHandler. That's why it is called "service activator".
You probably need to make yourself familiar with EIP first of all: https://www.enterpriseintegrationpatterns.com/ to understand what is messaging and why there are endpoints and channels in between. Then you go to Spring Integration docs: https://docs.spring.io/spring-integration/docs/current/reference/html/index.html and realize for yourself that this framework provides a bunch of out-of-the-box components for this or that EIP which may be registered automaticaly in the application context by just declaring some annotation.

#Async and #Transaction aspect order

Using Spring Boot 2.1.1.RELEASE / Spring Framework 5.1.4, I have an application with #Async and #Transactional annotations enabled through:
#EnableAsync(mode = AdviceMode.ASPECTJ)
#EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
When running a method that is annotated with both, first the transaction is created and then the asynchronous execution starts. So, the actual method body is not executed inside the transaction.
#Transactional
#Async
public void myAsyncMethod() {
// asynchronous database stuff
}
How can I configure spring / the aspects to actually execute in an order that makes sense, e.g. start the transaction on the new thread?
On a side note, with the older Spring Boot 1.5.17 / Spring Framework 4.3.20 it actually worked.
Demo: https://github.com/jaarts/spring-asynctransaction-demo
In Spring 5 Async advice is always execited first. See AsyncAnnotationBeanPostProcessor
public AsyncAnnotationBeanPostProcessor() {
setBeforeExistingAdvisors(true);
}
After that on superclass in postProcessAfterInitialization when advisors aplies code executes
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
}
On #EnableTransactionManagement#order javadoc says
Indicate the ordering of the execution of the transaction advisor
but on #EnableAsync
Indicate the order in which the AsyncAnnotationBeanPostProcessor should be applied.

Spring data - Manual implementation

Is it possible to write my own function implementation along usage of spring repositories?
I would like to actually implement the function
getUserByFirstName()
and not get it automagically.
While i still want to get
getUserById()
automagically from spring-data.
1) is it possible?
2) is it possible to achieve logging for all methods spring data automagically generates? (or should i write them manually with
logger.log("entering method ...");
See section 1.3 of the manual for the first requirement:
http://docs.spring.io/spring-data/jpa/docs/1.4.2.RELEASE/reference/html/repositories.html#repositories.single-repository-behaviour
For the second requirement I guess some AOP based solution might work for you well here. See here for example using Spring's AOP support:
logging with AOP in spring?
Yes, you can!!!
There is an amazing feature in Spring data that allows this:
Create an interface with your custom method:
public interface UserRepositoryCustom {
User getUserByFirstName();
}
Make your Spring Data interface extends this new interface, as well as the Spring data crud interface (or JPA, Mongo or whatever spring data interface you're extending):
public interface MySpringDataRepository extends CrudRepository<User, Long>, UserRepositoryCustom {
}
Create a class that implements only your custom interface. The name of the class must be Impl, for instance: UserRepositoryImpl:
public class MySpringDataRepositoryImpl implements UserRepositoryCustom {
public User getUserByFirstName(){
//Your custom implementation
}
}
Now, you only need to inject the Spring data repository in your service and you can use both methods: the spring-data implemented method and your custom implemented method:
#Inject private MySpringDataRepository myRepository;
That's it!!
Look at this section in the documentation:
Spring Data Custom implementations

Service activator method mapping using #Header annotation in Spring Integration

I'm developing web app using Spring Integration to route my messages, but I have some problems with passing my header value. My message goes through router and service activator.
The header value is available in a routing method of my router so it seems to be ok. Let's assume that it is not a problem (I checked this by disabling my service activator).
When it comes to my service activator method the following error is thrown:
"Failed to find any valid Message-handling methods named process on target class MyService."
my-spring-integration.xml
<channel id="route" />
<service-activator method="process" input-channel="route" ref="myService" output-channel="myOutputChannel" />
MyRouter.java
#Component
public class MyRouter {
public String router(String message, #Header("isValid") boolean isValid) {
// isValid is "true"
return "route";
}
}
MyService.java
#MessageEndpoint
#Transactional
public class MyService {
public void process(String message, #Header("isValid") boolean isValid) {
...
}
}
Why is that? Are headers values erased after routing? Or my configuration is wrong? I tried to add #ServiceActivator annotation to my process method, but it didn't help.
Any help will be greatly appreciated.
I would guess that this is caused by having an #Transactional annotation on a Service which doesn't implement any interfaces.
Spring will implement the transactional logic using JDK dynamic proxies, these rely on proxied classes implementing suitable interfaces. There is a Spring blog about this here.
To fix this I would suggest that you create an interface called MyService with a single method called process. Then have you service implement this interface.
I'm working with legacy code and it was probably caused by old spring integration version. My application support '#Headers', but it doesn't support '#Header' annotation. #Header annotation was accepted in my router which is interface and not in my service activator which does not implement any interface. I suspect it was caused by old version of spring integration or cglib.

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