I'm trying to call a method in Spring-powered bean asynchronously using #Async. I defined an executor in XML:
<task:executor id="emailTasksExecutor" pool-size="1" />
and here is my method:
#Override
#Async("emailTasksExecutor")
public void sendEmail()
{
...
}
And the method does not get called at all when I use qualifier (emailTasksExecutor). However, if I remove it, everything works ok. But in this case the default executor is used and I need to change this behaviour.
I thought the problem is that my class does not implement any interfaces, and something went wrong with proxies. But extracting the interface did not help.
So, the problem was my maven-aspectj-plugin. I found the solution here. All I need to do is to add mode="aspectj" to the task:annotation-driven.
Related
I'm using spring boot. I was new to spring and started a spring project. So I didn't know about pre defined repositories (JPA, CRUD) which can be easily implemented. In case, I wanted to save a bulk data, so I use for loop and save one by one, Its taking more time. So I tried to use #Async. But it doesn't also work, is my concept wrong?
#Async has two limitation
it must be applied to public methods only
self-invocation – calling the async method from within the same class won’t work
1) Controller
for(i=0;i < array.length();i++){
// Other codes
gaugeCategoryService.saveOrUpdate(getEditCategory);
}
2) Dao implementation
#Repository
public class GaugeCategoryDaoImpl implements GaugeCategoryDao {
// Other codings
#Async
#Override
public void saveOrUpdate(GaugeCategory GaugeCategory) {
sessionFactory.getCurrentSession().saveOrUpdate(GaugeCategory);
}
}
After removing #Async , it working normally. But with that annotation it doesn't work. Is there any alternative method for time consuming? Thanks in advance.
the #Async annotation creates a thread for every time you call that method. but you need to enable it in your class using this annotation #EnableAsync
You also need to configure the asyncExecutor Bean.
You can find more details here : https://spring.io/guides/gs/async-method/
In my opinion, there are several issues with your code:
You overwrite the saveOrUpdate() method without any need to do so. A simple call to "super()" should have been enough to make #Async work.
I guess that you somewhere (within your controller class?) declare a transactional context. That one usually applies to the current thread. By using #Async, you might leave this transaction context as (because of the async DAO execution), the main thread may already be finished when saveOrUpdate() is called. And even though I currently don't know it exactly, there is a good change that the declared transaction is only valid for the current thread.
One possble fix: create an additional component like AsyncGaugeCategoryService or so like this:
#Component
public class AsyncGaugeCategoryService {
private final GaugeCategoryDao gaugeCategoryDao;
#Autowired
public AsyncGaugeCategoryService(GaugeCategoryDao gaugeCategoryDao) {
this.gaugeCategoryDao = gaugeCategoryDao;
}
#Async
#Transactional
public void saveOrUpdate(GaugeCategory gaugeCategory) {
gaugeCategoryDao.saveOrUpdate(gaugeCategory);
}
}
Then inject the service instead of the DAO into your controller class. This way, you don't need to overwrite any methods, and you should have a valid transactional context within your async thread.
But be warned that your execution flow won't give you any hint if something goes wrong while storing into the database. You'll have to check the log files to detect any problems.
My goal is to execute some code each time a method with a particular annotation completes its execution. I have the following:
#Aspect
public class MonitoringAspect {
#After("#annotation(MonitorExecution)")
public void onFinished(JoinPoint jp) {
System.out.println("called!");
}
}
The code of the MonitorExecution annotation is as follows:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MonitorExecution {
}
This happens inside a Spring4 application and I have declared the MonitoringAspect as a bean like:
<bean id="monitoringAspect" class="com.....MonitoringAspect" />
<aop:aspectj-autoproxy proxy-target-class="true">
<aop:include name="monitoringAspect"/>
</aop:aspectj-autoproxy>
I have a public method inside a general-purpose class (i.e. not managed by spring / not a component) that is annotated with the #MonitorExecution annotation. I have successfully verified that the aforementioned method gets called, but the aspect is never triggered. Any ideas what might be the issue?
aspectj-autoproxy means that proxy classes will be created for each Spring managed bean (using JDK dynamic proxies or CGLIB) and using these proxies you are able to intercept methods invocation. Thus, if your annotated method is method of a class outside Spring Context, aspect will not work
Despite it if you still want to intercept it, you will have to use AspectJ only or in conjunction with Spring. For second option you will have to enable load-time weaving in your spring configuration
Have a look documentation for details:
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop
Note: I have purposefully removed words from the names of classes and objects, so please excuse the horribly names in my code examples
I've got a test class that sets up my application using some test Spring context files. The application is a wrapper to a web service.
As this is a test, I have mocked the main interface to the web service in question (the ITransporter class). This gives me the ability to set expectations so that I can check that the requests sent to the web service are: in the expected format; have the expected fields complete; etc...
My mock is defined in a file called test-beans-context.xml and is passed into some service beans, as follows:
<bean id="mockTransporter" class="org.easymock.EasyMock" factory-method="createMock" scope="singleton">
<constructor-arg index="0" value="transport.ITransporter" />
</bean>
<bean id="accountService" class="service.AccountService">
<property name="transporter" ref="mockTransporter" />
</bean>
This context file is used in 2 places. (And I fear this is where my problem arises.)
The first being the test class, which is defined as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration( locations={"classpath:test-beans-context.xml"} )
public class AbstractIntegrationTest {
#Autowired
private ITransporter mockTransporter;
//Some tests that perform expectations like the following:
// EasyMock.reset( this.mockTransporter );
// EasyMock.expect( this.mockTransporter.sendRequest( EasyMock.capture(this.requestXmlCapture) ) ).andReturn( responseXml );
}
The second place is in a class that is within the logical trail for getting to sending the request. It loads a separate XML context file /lite-api-context.xml that then imports the test one in my test set up.
public class Factory implements IFactory {
public Factory() {
context = new ClassPathXmlApplicationContext("/lite-api-context.xml");
}
#Override
public IAccountService getAccountService() {
return (IAccountService) context.getBean("accountService");
}
}
And lite-api-context.xml includes this:
<import resource="classpath:/test-beans-context.xml" />
My problem is that in the test class, I'm getting a different instance of the mocked ITransporter to the one that is ultimately being used by my other services. So the expectations I set up are never actually executed as the mocks end up being different instances.
Is there a way to ensure I get the same instance in both places?
Or am I going to have to create my own singleton test implementation of the ITransporter interface? (Basically creating a stub that behaves exactly like my mock does now.)
EDIT: (Answer)
As The Thom said, it appears I need to create my own class to manage the mock.
I wanted to add my solution here too in case anyone stumbled across a similar problem.
Just wrote a quick static class like this:
public class MockTransporter {
private static ITransporter mockTransporter = EasyMock.createMock(ITransporter.class);
public static final ITransporter getInstance() {
return mockTransporter;
}
}
And had to change the XML config to this:
<bean id="mockTransporter" class="MockTransporter" factory-method="getInstance" />
Oh yeah, that's a problem. When you create a new context that's like creating a new object space for Spring. The one created in your XML file is different from the one created in your handmade context. They will always produce different variables.
I've been burned on that one before.
You're only hope if you want the same ones is to manage your own singletons.
The ideal way to solve this problem would be to create the Factory as a Spring bean as well, and inject the AccountService into the Factory bean.
In general context.getBean() should be avoided in production code because it harms the concept of Inversion of Control (for more information see: Why is Spring's ApplicationContext.getBean considered bad?). It's okay to use it in test code though.
I am using Spring's task executor to schedule a method at regular interval.
public class ABC{
#Scheduled(fixedDelay=100000)
public void test(){
}
}
It doesn't work with simple bean declaration for the class ABC.
<bean id="abc" class="com.test.ABC" />
If I put component scan then it works fine.
<context:component-scan base-package="com.test"/>
<context:annotation-config/>
What could be the reason?
I think, both should work fine as Component scan is just an alternative for defining individual bean. might be something wrong from my side.
Let me know if my thoughts are not correct.
Thanks,
I have a static method I have no control over: MyUtils.getServiceURL() which returns a URL. I need to extract just the port from this URL to set a property on a bean:
<bean id="myBean>
<property name="defaultPort" value="?????"/>
</bean>
I can get the string value of the URL as a bean like this:
<bean id="serviceURL" class="MyUtils" factory-method="getServiceURL" />
I'm probably just going to write a method to parse the URL in myBean and extract the port. I was wondering if there was a way to avoid having to do this, and configure this directly in the spring context?
No need for custom classes, or parsers. Remember, a bean is just a class with get/is/set methods. A java.net.URL class qualifies as such.
Solution: Use a java.net.URL as a Spring-configurable bean and call it's getPort method.
Remember, in Spring, you can wire anything as a bean very easily so long as it sports methods using the get/is/set Bean convention. The java.net.URL class does such a thing.
** warning ** I'm just typing this out of my a$$, you'll have to check for any syntax shenanigans that I might be introducing in this Spring-config pseudo-code. One thing that is certain is that the concept will work with Spring 2.5 and that it relies on the util schema.
If you are using an older version of Spring, you'll have to use a PropertyPathFactoryBean. If you are using Spring 3.0, you'll want to use Spring expression language (EL), but I can't comment on the later since I'm not familiar with Spring 3.0.
In java:
int port = (new URL(MyUtils.getServiceURL()).getPort()
In Spring:
<bean id="serviceURL" class="MyUtils" factory-method="getServiceURL" />
<bean id="myURL" class="java.net.URL">
<constructor-arg>
<ref-bean="serviceURL"/>
</constructor-arg>
</bean>
<util:property-path id="defaultPort" path="myURL.port"/>
<bean id="myBean>
<property name="defaultPort" ref="defaultPort"/>
</bean>
There might be a way to consolidate all these four expressions into three or less, don't know if that will improve readability, though. The concept remains the same, though. Treat a java.net.URL instance as a bean, set its URL via its constructor, and get a hold (via Spring) of its getPort() method.
** edit **:
If you are using Spring 2.5 you can create an inline groovy bean that does all that for you. I've seen people doing that as integration glue to get rid of multitude of temp Spring bean place holders. That's the best choice IMO when you need to define a class (when it's simpler than just using Spring tags) and when you know such a class won't be used outside of Spring wiring of things.
Not I can think of. Either way, you probably have to write something to parse the port out. Since you have no control of that static method, perhaps you may want to utilize the adapter pattern to hide that static method. Doing so also makes your code easier to test because you can easily mock that external API out. For example:-
public interface URLServiceAdapter {
int getServiceURLPort();
}
public class URLServiceAdapterImpl implements URLServiceAdapter {
public int getServiceURLPort() {
return MyUtils.getServiceURL().getPort();
}
}
Your beans will then rely on your adapter class instead of MyUtils.getServiceURL() directly:-
<bean id="urlServiceAdapter" class="project.URLServiceAdapterImpl" />
That way, you can do something like this:-
#Autowired
private UrlServiceAdapter urlServiceAdapter;
...
bean.setDefaultPort(urlServiceAdapter.getServiceURLPort());
SpEL is your friend.
<bean id="myBean>
<property name="defaultPort"
value='#{ T(com.foo.MyUtils).getServiceURL().split(":")[2].split("/")[0] }'/>
</bean>
Enjoy,