Is it possible to use callbacks with Spring to that they are managed by application context?
My problem is when a service is used from outer by #Autowired, but within that service there is a callback defined using new operator.
The following example executes a method that is worth retrying. Spring offers a RetryCallback for this case (I know this could be acchieved differently, but just to illustrate my callback problem).
#Service
class MyService {
//main method invoked
void run(DataVO dataVO) {
//new operator not usable in spring context
RetryCallback<Object> retryCallback = new RetryCallback<Object>() {
#Override
public Object doWithRetry(RetryContext context) throws Exception {
return createBooking(dataVO);
}
};
}
private Object createBooking(DataVO dataVO) {
//creates the booking, worth retry on specific failures
//uses further injected/autowired services here
}
}
Is it possible to refactor this snippet so that the callback is managed by spring/injected/autowired?
Make your service implement the callback interface :
#Service
class MyService implements RetryCallback<Object> {
//main method invoked
void run(DataVO dataVO) {
}
#Override
public Object doWithRetry(RetryContext context) throws Exception {
return createBooking(dataVO);
}
private Object createBooking(DataVO dataVO) {
//creates the booking, worth retry on specific failures
//uses further injected/autowired services here
}
}
Related
I am having troubles invoking a method asynchronously in Spring, when the invoker is an embedded library receiving notifications from an external system. The code looks as below:
#Service
public class DefaultNotificationProcessor implements NotificationProcessor {
private NotificationClient client;
#Override
public void process(Notification notification) {
processAsync(notification);
}
#PostConstruct
public void startClient() {
client = new NotificationClient(this, clientPort);
client.start();
}
#PreDestroy
public void stopClient() {
client.stop();
}
#Async
private void processAsync(Notification notification) {
// Heavy processing
}
}
The NotificationClient internally has a thread in which it receives notifications from another system. It accepts a NotificationProcessor in its constructor which is basically the object that will do the actual processing of notifications.
In the above code, I have given the Spring bean as the processor and attempted to process the notification asynchronously by using #Async annotation. However, it appears the notification is processed in the same thread as the one used by NotificationClient. Effectively, #Async is ignored.
What am I missing here?
#Async (as well as #Transactional and other similar annotations) will not work when the method is invoked via this (on when #Async is used for private methods*), as long as you do not use real AspectJ compiletime or runtime weaving.
*the private method thing is: when the method is private, then it must been invoked via this - so this is more the consequence then the cause
So change your code:
#Service
public class DefaultNotificationProcessor implements NotificationProcessor {
#Resource
private DefaultNotificationProcessor selfReference;
#Override
public void process(Notification notification) {
selfReference.processAsync(notification);
}
//the method must not been private
//the method must been invoked via a bean reference
#Async
void processAsync(Notification notification) {
// Heavy processing
}
}
See also the answers for: Does Spring #Transactional attribute work on a private method? -- this is the same problem
I am writing a Spring Boot Application. I want to audit methods with my annotation #AuditMetod: For example I have method foo() with the annotation:
#AuditMetod(name = "SomeValue")
foo() {...}
I want to handle and audit such methods like this (the simplest example):
auditMethod(Method method) {
if (method.hasAnnotation(AuditMethod.class)) {
System.out.println (method.getName() + " was called at " + new Date())
}
}
upd
Thanks to #Karthikeyan #Swapnil Khante and #misha2048 I understood, that I need to use AOP. But I have 2 problems:
The only method in Aspect class in not being called and I don't see the inscription "----------ASPECT METHOD IS CALLED-----------" in log
How can I check in aspect method what method it is intercepting. To get an instance of Method class.
Now I have the following code:
Controller:
#PostMapping
#LoggingRest(executor = "USER", method = "CREATE", model = "SUBSCRIPTION")
public ResponseEntity<?> create(#Valid #RequestBody SubscriptionRequestDto dto) {
...
}
Aspect:
`#Aspect
#Slf4j
#Component
public class AuditAspect {
#Pointcut(value = "#annotation(com.aspect.annotations.LoggingRest)")
public void auditMethod(ProceedingJoinPoint proceedingJoinPoint) {
log.info("----------ASPECT METHOD IS CALLED------------");
}`
And annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface LoggingRest {
String executor() default "SYSTEM";
String method() default "";
String model() default "";
}
Auditing is a cross-cutting concern and can be handled using AOP.
Another solution would be to use a low-level solution by writing a custom annotation and using a Spring interceptorto write your business logic.
To use the Spring interceptor you will need to implement the HandlerInterceptor interface
Example of the annotation
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Audit {
boolean active() default true;
}
Interceptor example
#Component
public class AuditInterceptor implements HandlerInterceptor {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Audit annotation = handlerMethod.getMethodAnnotation(Audit.class);
if (annotation != null && annotation.active()) {
// your business logic
}
}
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
check this interceptor example
I think one of the solutions here, as #Karthikeyan mentioned, is to use Spring AOP.
If you are not aware a brief introduction - spring-aop module implements the aspect oriented programming paradigm. We extract some common functionality, that we generally want to apply to some subset of functions/methods, to an entity called Aspect (see class annotated with #Aspect). This class will contain out cross-cutting functionality - such as auditing, for instance we want to audit the methods execution time, lets say. We just put the code to be executed, the condition, which tell the spring what exact beans methods should be affect by this aspect, see below.
For example, if I can audit the method execution duration with the following very simple example (in my case I said that any public method, returning void inside the Class com.example.stackoverflow.BusinessLogicClass must be inspected by this Aspect):
#SpringBootApplication
#EnableAspectJAutoProxy
public class StackoverflowApplication implements ApplicationRunner {
#Autowired
private BusinessLogicClass businessLogicClass;
public static void main(String[] args) {
SpringApplication.run(StackoverflowApplication.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {
businessLogicClass.test();
}
}
#Aspect
#Component
class MyAspectLogicClass {
#Around("execution(public void com.example.stackoverflow.BusinessLogicClass.*(..))")
public Object hangAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long before = System.currentTimeMillis();
Object returnedValue = proceedingJoinPoint.proceed();
long after = System.currentTimeMillis();
System.out.printf("Retruned in '%s' ms %n", (after - before));
return returnedValue;
}
}
#Component
class BusinessLogicClass {
public void test() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
In my case, I will get the time before method execution, then by the means of
proceedingJoinPoint.proceed() call I delegate the execution to the real method, and then, once I get the response back, I will get the current system time and calculate the execution time, fairly simple.
I hope I have at least directed you somewhere, if you are looking for documentation, this are the resources I suggest you should look for:
https://docs.spring.io/spring-framework/docs/2.5.x/reference/aop.html offical spring doc (stale a bit, but there are some valuable things to learn)
https://docs.spring.io/spring-framework/docs/4.3.15.RELEASE/spring-framework-reference/html/aop.html is more fresh doc
Hope it helped :)
The problem was in right annotation. In Aspect class I tried #Around and everything works as I need.
#Aspect
#Slf4j
#Component
public class AuditAspect {
#Around(value = "#annotation(com.aspect.annotations.LoggingRest)")
public void auditMethod(ProceedingJoinPoint proceedingJoinPoint) {
var method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
log.info("----------ASPECT METHOD IS CALLED------------");
}
}
For getting a Method instance I use fallowing code
Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
I've implemented a JAX-RS server application using Jersey 2.24.
I use the Guice-HK2 bridge so that the controller classes (those annotated with #Path) are injected with dependencies from Guice, not Jersey/HK2.
However, HK2 still creates instances of the #Path annotated classes itself.
Is there a way I can plug into Jersey/HK2 so that I'm notified when a #Path annotated class is created? Like some sort of lifecycle listener? Every time a #Path annotated class is created by Jersey/HK2 I want to do some registering/logging of that class.
If Guice were doing the actual creation of the #Path annotated class I think I could do it using a generic Provider but that's not available in this case, since Jersey/HK2 is creating the actual instance.
Thank you!!
I think the least intrusive way would be to just use AOP. HK2 offers AOP. What you can do is create a ConstructorInterceptor. Something like
public class LoggingConstructorInterceptor implements ConstructorInterceptor {
private static final Logger LOG
= Logger.getLogger(LoggingConstructorInterceptor.class.getName());
#Override
public Object construct(ConstructorInvocation invocation) throws Throwable {
Constructor ctor = invocation.getConstructor();
LOG.log(Level.INFO, "Creating: {0}", ctor.getDeclaringClass().getName());
// returned instance from constructor invocation.
Object instance = invocation.proceed();
LOG.log(Level.INFO, "Created Instance: {0}", instance.toString());
return instance;
}
}
Then create a InterceptorService to only use the interceptor for classes annotated with #Path
public class PathInterceptionService implements InterceptionService {
private static final ConstructorInterceptor CTOR_INTERCEPTOR
= new LoggingConstructorInterceptor();
private final static List<ConstructorInterceptor> CTOR_LIST
= Collections.singletonList(CTOR_INTERCEPTOR);
#Override
public Filter getDescriptorFilter() {
return BuilderHelper.allFilter();
}
#Override
public List<MethodInterceptor> getMethodInterceptors(Method method) {
return null;
}
#Override
public List<ConstructorInterceptor> getConstructorInterceptors(Constructor<?> ctor) {
if (ctor.getDeclaringClass().isAnnotationPresent(Path.class)) {
return CTOR_LIST;
}
return null;
}
}
Then just register the InterceptionService and ConstructorInterceptor with the DI system
new ResourceConfig()
.register(new AbstractBinder(){
#Override
public void configure() {
bind(PathInterceptionService.class)
.to(InterceptionService.class)
.in(Singleton.class);
bind(LoggingConstructorInterceptor.class)
.to(ConstructorInterceptor.class)
.in(Singleton.class);
}
});
See complete example in this Gist
See Also:
HK2 documentation on AOP
Basically these two approaches into one:
Can Guice automatically create instances of different classes based on a parameter?
Guice injecting only some of the constructor
For example:
User operation handlers are created with mapped and assisted injections, i.e. each needs some static bindings as well as an operation context that is created dynamically from a request.
class OpHandler { void handle()... }
class SendHandler extends OpHandler {
public SendHandler(DAL dal, SendContext context) { ... }
}
class ReceiveHandler extends OpHandler {
public ReceiveHandler(DAL dal, ReceiveContext context) { ... }
}
servlet:
onGet() {
op = resolveOp();
switch (op) {
SEND: create SendContext and pass it somehow to ioc.getInstance(SendHandler.class)
RECEIVE: create ReceiveContext and pass it somehow to ioc.getInstance(ReceiveHandler.class)
}
}
Let's say I have a class in my web app called class "Foo". It has an initialise() method that is called when the bean is created using Spring. The initialise() method then tries to load an external service and assign it to a field. If the service could not be contacted, the field will be set to null.
private Service service;
public void initialise() {
// load external service
// set field to the loaded service if contacted
// set to field to null if service could not be contacted
}
When someone calls the method get() on the class "Foo" the service will be invoked if it was started in the initialise() method. If the field for the service is null, I want to try and load the external service.
public String get() {
if (service == null) {
// try and load the service again
}
// perform operation on the service is service is not null
}
Is it possible that I may have sync issues if I would do something like this?
toolkit's answer is correct. To solve the problem, just declare your Foo's initialise() method to be synchronized. You could refactor Foo as:
private Service service;
public synchronized void initialise() {
if (service == null) {
// load external service
// set field to the loaded service if contacted
}
}
public String get() {
if (service == null) {
initialise(); // try and load the service again
}
// perform operation on the service is service is not null
}
Yes, you will have a sync problem.
Lets assume you have single servlet:
public class FooServlet extends HttpServlet {
private MyBean myBean;
public void init() {
myBean = (MyBean) WebApplicationContextUtils.
getRequiredWebApplicationContext(getServletContext()).getBean("myBean");
}
public void doGet(HttpRequest request, HttpResponse response) {
String string = myBean.get();
....
}
}
class MyBean {
public String get() {
if (service == null) {
// try and load the service again
}
// perform operation on the service is service is not null
}
}
And your bean definition looks like:
<bean id="myBean" class="com.foo.MyBean" init-method="initialise" />
The problem is that your servlet instance is used by multiple request threads. Hence, the code block guarded by service == null may be entered by multiple threads.
The best fix (avoiding double-checked-locking etc) is:
class MyBean {
public synchronized String get() {
if (service == null) {
// try and load the service again
}
// perform operation on the service is service is not null
}
}
Hope this makes sense. Drop a comment if not.