Spring AOP: exchanging information between methods - java

Suppose that I have a class called MyServlet, whose purpose is to respond to a user request:
#Component
public class MyServlet
{
public void accept(String clientName, int clientID)
{
System.out.println("Processing client:" + clientName + " with ID: " + clientID);
}
}
Generally speaking, serving the request of a user might be something we want to log before we attempt it to debug our application. So I would really like it if I could have this behavior happen transparently before accept() is ever called. For this person, a Helper class can provide a logging functionality, which we will decorate with #Before:
#Aspect
#Component
#EnableAspectJAutoProxy
public class Helper
{
#Before("execution(public void show())")
public void log()
{
System.out.println("Logging data...");
}
}
But it would be really useful for me to be able to get the information that is provided to accept() (in this case, a String and an int) and pass it into log(), since it would allow me to log exactly the user and their ID into whatever logging store I use. How can I achieve this?

You can access proxied method's arguments by injection of JoinPoint instance and invoking getArgs() method on it. Sample snippet below.
#Before("execution(* com.sample.SomeClass.doSometning(..))")
public void doSomethingBefore(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
for (Object arg: args) {
// do whatever you like with the arguments
}
}

Related

Mockito - verify a method with Callable<> as parameter [duplicate]

I have a simple scenario in which am trying to verify some behavior when a method is called (i.e. that a certain method was called with given parameter, a function pointer in this scenario). Below are my classes:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
AppBootStrapper bootStrapper = context.getBean(AppBootStrapper.class);
bootStrapper.start();
}
}
#Component
public class AppBootStrapper {
private NetworkScanner networkScanner;
private PacketConsumer packetConsumer;
public AppBootStrapper(NetworkScanner networkScanner, PacketConsumer packetConsumer) {
this.networkScanner = networkScanner;
this.packetConsumer = packetConsumer;
}
public void start() {
networkScanner.addConsumer(packetConsumer::consumePacket);
networkScanner.startScan();
}
}
#Component
public class NetworkScanner {
private List<Consumer<String>> consumers = new ArrayList<>();
public void startScan(){
Executors.newSingleThreadExecutor().submit(() -> {
while(true) {
// do some scanning and get/parse packets
consumers.forEach(consumer -> consumer.accept("Package Data"));
}
});
}
public void addConsumer(Consumer<String> consumer) {
this.consumers.add(consumer);
}
}
#Component
public class PacketConsumer {
public void consumePacket(String packet) {
System.out.println("Packet received: " + packet);
}
}
#RunWith(JUnit4.class)
public class AppBootStrapperTest {
#Test
public void start() throws Exception {
NetworkScanner networkScanner = mock(NetworkScanner.class);
PacketConsumer packetConsumer = mock(PacketConsumer.class);
AppBootStrapper appBootStrapper = new AppBootStrapper(networkScanner, packetConsumer);
appBootStrapper.start();
verify(networkScanner).addConsumer(packetConsumer::consumePacket);
verify(networkScanner, times(1)).startScan();
}
}
I want to verify that bootStrapper did in fact do proper setup by registering the packet consumer(there might be other consumers registered later on, but this one is mandatory) and then called startScan. I get the following error message when I execute the test case:
Argument(s) are different! Wanted:
networkScanner bean.addConsumer(
com.spring.starter.AppBootStrapperTest$$Lambda$8/438123546#282308c3
);
-> at com.spring.starter.AppBootStrapperTest.start(AppBootStrapperTest.java:24)
Actual invocation has different arguments:
networkScanner bean.addConsumer(
com.spring.starter.AppBootStrapper$$Lambda$7/920446957#5dda14d0
);
-> at com.spring.starter.AppBootStrapper.start(AppBootStrapper.java:12)
From the exception, clearly the function pointers aren't the same.
Am I approaching this the right way? Is there something basic I am missing? I played around and had a consumer injected into PacketConsumer just to see if it made a different and that was OK, but I know that's certainly not the right way to go.
Any help, perspectives on this would be greatly appreciated.
Java doesn't have any concept of "function pointers"; when you see:
networkScanner.addConsumer(packetConsumer::consumePacket);
What Java actually compiles is (the equivalent of):
networkScanner.addConsumer(new Consumer<String>() {
#Override void accept(String packet) {
packetConsumer.consumePacket(packet);
}
});
This anonymous inner class happens to be called AppBootStrapper$$Lambda$7. Because it doesn't (and shouldn't) define an equals method, it will never be equal to the anonymous inner class that the compiler generates in your test, which happens to be called AppBootStrapperTest$$Lambda$8. This is regardless of the fact that the method bodies are the same, and are built in the same way from the same method reference.
If you generate the Consumer explicitly in your test and save it as a static final Consumer<String> field, then you can pass that reference in the test and compare it; at that point, reference equality should hold. This should work with a lambda expression or method reference just fine.
A more apt test would probably verify(packetConsumer, atLeastOnce()).consumePacket(...), as the contents of the lambda are an implementation detail and you're really more concerned about how your component collaborates with other components. The abstraction here should be at the consumePacket level, not at the addConsumer level.
See the comments and answer on this SO question.

What is a good design to execute the methods based on boolean values in Database in Java?

We have few rules, which are Implemented as methods in Java. But sometimes we need to bypass the rules. So for each rule, we have a boolean Indicator to indicate whether to execute or not. What can be a good design to map the methods to boolean values in Database and execute methods based on the boolean values.
Below is sample template
1 Rule1 true
2 Rule2 false
3 Rule3 true
4 Rule4 true
So, now I need to execute method1(), method3() and method4() respectively.
One Simple way can be using If(rulee == true) executeMethod();
Second is using a Switch to execute the cases (method calls)
Note: We may need to execute the methods in different locations(methods). So please dont consider that all the methods will be called from a single method.
Can I make use of AOP by any chance?
You could define the basic interface as
public interface Rule {
boolean canExecute();
void execute();
}
and convert the methods into Rule interface implementations. The boolean value in the database would map to canExecute() return value.
This would be a good idea if methods are becoming complex, there's more than a few of them and the parent class is starting to look like a God Object.
Use Java 8 Stream api and Enums.
public class Main {
public enum Rule {
RULE1 {
#Override
public void doWork() {
}
},
RULE2 {
#Override
public void doWork() {
}
};
public abstract void doWork();
}
public static void main(String[] args) {
List<String> rules = new ArrayList<>();
rules.stream()
.map(Rule::valueOf)
.forEach(Rule::doWork);
}
}
You can just call all methods and do the validation part within the method implementation, e.g.:
void rule1(Object... args){
if (!applyRule1){
return;
}
...
}
With that approach, you can reduce cyclomatic complexity and prevent tools such as PMD from complaining.
Another approach is to store the method names as strings in the database. If your database supports arrays, that's particularly easy.
Then in Java you can set up an executor that accepts a String name and execute the respective rule:
import java.util.List;
import static java.util.Arrays.asList;
public class ByNameExecutor {
enum Rule {
Rule1 { #Override void rule() { System.out.println("Executed rule 1"); } },
Rule2 { #Override void rule() { System.out.println("Executed rule 2"); } },
Rule3 { #Override void rule() { System.out.println("Executed rule 3"); } },
Rule4 { #Override void rule() { System.out.println("Executed rule 4"); } },
;
abstract void rule();
}
public void execute(String ruleName) {
Rule.valueOf(ruleName).rule();
}
public void execute(List<String> ruleNames) {
ruleNames.stream().forEach(this::execute);
}
public static void main(String [] args) {
String [] methodList = { "Rule1", "Rule2", "Rule4" };
new ByNameExecutor().execute(asList(methodList));
}
}
An advantage of this approach is that you don't need to change the database schema to add a rule. Just start storing the new rule's string name. A disadvantage is that if you need to query on presence of or absence of a given rule, the database must support indexes over arrays.
Update: I replaced Consumer interface with Runnable in my original answer, because it aligns with example in the question better.
You can try to upgrade your Rule entity, here is an idea using Runnable interface:
class Rule {
private boolean isActive;
private Runnable runnable;
public Rule(boolean isActive, Runnable runnable) {
this.isActive = isActive;
this.runnable = runnable;
}
public void executeIfActive() {
if (isActive) {
runnable.run();
isActive = false;
}
}
}
Example of the use:
public class Demo {
public static void main(String[] args) {
Demo demo = new Demo();
List<Rule> rules = List.of(new Rule(true, demo::m1), new Rule(false, demo::m2));
rules.forEach(Rule::executeIfActive);
}
void m1() { ... }
void m2() { ... }
}
demo::m1 is a method reference that would invoke the method demo.m1(), and the same for m2.
If I understand the problem correctly then it should work. You can have a method like below and call it from anywhere.
Or these booleans can also be a rule and you can add multiple methods in one IF condition
void executeMethods(boolean m1, boolean m2, boolean m3, boolean m4){
if(m1) m1();
if(m2) m2();
if(m3) m3();
if(m4) m4();
}
executeMethods(true,false,false,true);
Instead of store Boolean you can store method names in this field accordingly. Then all you need to do would be invoke that method using reflection.
Table:
Id RULE_NAME METHOD_NAME
1 Rule1 method1
2 Rule2
3 Rule3 method3
4 Rule4 method4
The method can be invoked like this:
ResultSet srs = stmt.executeQuery("SELECT METHOD_NAME from table");
while (srs.next()) {
String methodName = srs.getString("METHOD_NAME");
if (!TextUtils.isEmpty(methodName)) {
Class<?> c = Class.forName("class name");
Method method = c.getDeclaredMethod(methodName, parameterTypes); // method name will be fetched from Database
method.invoke(objectToInvokeOn, params);
}
}
Reflection API > Invoking Methods
Lets solve this problem with a database driven approach, and Spring AOP.
You have several hundred rules, and do not wish to pollute the current code with boilerplate code like void method1() { if (!rule1) return; .. do method } or have to create additional interfaces which all rule based methods must implement.
Spring AOP provides a means to leave the current base in tact, and instead have methods intercepted (via a proxy) to determine if the method should run or not. You write the proxy code once, and the only ongoing requirement is to keep the database up to date with new rules.
Step 1: Build a database schema which maps method names to boolean values
method_name VARCHAR(100), is_rule_active tinyint(1);
There will be one row for each rule. The row will contain the method name (as it appears in the java code) and a boolean true=active, false=not active.
Step 2: Build an interface to the database (DAO)
You need a simple abstraction to the database. Something like:
public interface RuleSelectionInterface {
boolean isRuleActive(String methodName);
}
The implementation will be basic DAO code, which will query for the row with method_name equal to methodName. For simplicity, and to demonstrate, I used a Map instead:
#Repository
public class RuleSelectionImpl implements RuleSelectionInterface {
Map<String, Boolean> rules;
public RuleSelectionImpl() {
rules = new HashMap<>();
rules.put("rule1Method", true);
rules.put("rule2Method", false);
}
#Override
public boolean isRuleActive(String methodName) {
if (!rules.containsKey(methodName))
return false;
return rules.get(methodName);
}
}
Step 3: Create a Spring AOP aspect
An aspect is created to intercept method calls, and determine when the call should be executed.
To allow execution to be continued, or aborted, you use an #Around advice, which will be passed the execution point (by means of a ProceedingJoinPoint) from which you can either abort (the proxy method simply returns) or run the code by using the proceed method.
There is some choice here on which methods should be intercepted (this is done by defining pointcuts). This example will intercept methods with names starting with rule:
#Around("execution(* rule*(..))")
You could intercept all methods, or methods based on naming patterns, etc. For a detailed understanding of how to create pointcuts to intercept methods refer to Spring AOP
Here is the AOP code, which is called upon method interception, and which uses your database rule interface to look up if the rule is active for this method name:
#Aspect
#Component
public class RuleAspects {
#Autowired
private RuleSelectionInterface rulesSelectionService;
#Around("execution(* rule*(..))")
public void ruleChooser(ProceedingJoinPoint jp) throws Throwable
{
Signature sig = jp.getSignature();
System.out.println("Join point signature = "+sig);
String methodName = sig.getName();
if (rulesSelectionService.isRuleActive(methodName))
jp.proceed();
else
System.out.println("Method was aborted (rule is false)");
}
}
Sample usage:
I created a simple class with two methods (however this approach works regardless of how many classes/methods you have rule based methods for).
#Component
public class MethodsForRules {
public void rule1Method() {
System.out.println("Rule 1 method");
}
public void rule2Method() {
System.out.println("Rule 2 method");
}
}
You will have noticed in the Map that rule1Method is set to true, and rule2Method is set to false.
When the code tries to run rule1Method and rule2Method:
MethodsForRules r; // Is a Spring managed bean.
r.rule1Method();
r.rule2Method();
Produces the following output:
Join point signature = void com.stackoverflow.aoparound.demo.MethodsForRules.rule1Method()
Rule 1 method <- Here is the method running
Join point signature = void
com.stackoverflow.aoparound.demo.MethodsForRules.rule2Method()
Method was aborted (rule is false) <- Here the method is aborted
Summary:
This demonstration has shown how Spring AOP can be used, in combination with a rules based interface, to intercept methods (by using a proxy), examine the method name which was intercepted, lookup the active status for this method, and either run the method, or abort it.

Java template method pattern

I am trying to implement something along the lines of the template method pattern within some JavaEE beans that do some processing work on a dataset.
Each processing bean takes the Job object, does some work then returns the updated job for the next bean (about 10 in total), each bean has a single method with the same name (doProcessing) and single argument (job)
I would like to perform some logging at the start and end of each beans 'doProcessing' method so that at the end of processing the Job contains logging info from each bean (stored in a hashmap or suchlike)
My current implementation looks something like this...
#Stateless
public class processingTaskOne(){
public void doProcessing(Job job){
//always called at beginning of method
String beanReport = "Info from Task 1: ";
for(int i=0; i<job.getDataArray().size();i++){
beanReport+="\n some more info";
//Do some processing work here
}
//always called at end of method
job.addNewReportSection(beanReport)
}
}
But I know that I can do better than this, using inheritance I should be able to create a superclass along the lines of...
public abstract class Reportable{
private String sectionReport;
public void preProcessing(Job job){
//Setup bean report, use reflection to get subclass name
}
public void postProcessing(Job job){
//Finish bean report and append to job
job.addNewReportSection(sectionReport)
}
public abstract doProcessing(){
//not sure how this should work
}
}
And any class that extends the superclass will automatically perform the pre/postprocessing actions...
#Stateless
public class processingTaskOne() extends Reportable{
public void doProcessing(Job job){
for(int i=0; i<job.getDataArray().size();i++){
super.sectionReport += "log some info"
//Do some processing work here
}
}
}
But I have been unable to work out how to implement this exactly, since all the examples refer to POJO's and as my beans are #Stateless there is no constructor.
Can someone provide some guidance on this? Am I barking up the wrong tree?
If I understood your question correctly, you can try the following:
public abstract class Reporting {
public void setUp(Job job) {
// set things up
}
public void tearDown(Job job) {
// post-processing stuff
}
public void process(Job job) {
setUp(job);
doProcessing(job);
tearDown(job);
}
public abstract void doProcessing(Job job);
}
public class Processor1 extends Reporting {
#Override
public void doProcessing(Job job) {
// business logic
}
}
and later, somewhere in your code, you should call not the doProcessing(), but rather the process() method of your base class.
Also, in case my interpretation was correct, you might be interested in using some aspect-oriented programming framework like AcpectJ or Spring AOP.

Joinpoint VS ProceedingJoinPoint in AOP using aspectJ?

Can any one tell me what is the difference between Joinpoint and Proceedingjoinpoint?
When to use Joinpoint and Proceedingjoinpoint in the method of aspect class?
I used the JoinPoint in my AspectJ class like:
#Pointcut("execution(* com.pointel.aop.test1.AopTest.beforeAspect(..))")
public void adviceChild(){}
#Before("adviceChild()")
public void beforeAdvicing(JoinPoint joinPoint /*,ProceedingJoinPoint pjp - used refer book marks of AOP*/){
//Used to get the parameters of the method !
Object[] arguments = joinPoint.getArgs();
for (Object object : arguments) {
System.out.println("List of parameters : " + object);
}
System.out.println("Method name : " + joinPoint.getSignature().getName());
log.info("beforeAdvicing...........****************...........");
log.info("Method name : " + joinPoint.getSignature().getName());
System.out.println("************************");
}
But what I see in other resources is:
#Around("execution(* com.mumz.test.spring.aop.BookShelf.addBook(..))")
public void aroundAddAdvice(ProceedingJoinPoint pjp){
Object[] arguments = pjp.getArgs();
for (Object object : arguments) {
System.out.println("Book being added is : " + object);
}
try {
pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
}
Here what will ProceedingJoinPoint do differently compare to 'JointPoint? Also what willpjp.proceed()` do for us?
An around advice is a special advice that can control when and if a method (or other join point) is executed. This is true for around advices only, so they require an argument of type ProceedingJoinPoint, whereas other advices just use a plain JoinPoint. A sample use case is to cache return values:
private SomeCache cache;
#Around("some.signature.pattern.*(*)")
public Object cacheMethodReturn(ProceedingJoinPoint pjp){
Object cached = cache.get(pjp.getArgs());
if(cached != null) return cached; // method is never executed at all
else{
Object result = pjp.proceed();
cache.put(pjp.getArgs(), result);
return result;
}
}
In this code (using a non-existent cache technology to illustrate a point) the actual method is only called if the cache doesn't return a result. This is the exact way the Spring EHCache Annotations project works, for example.
Another specialty of around advices is that they must have a return value, whereas other advice types must not have one.
#Around("execution(* com.mumz.test.spring.aop.BookShelf.addBook(..))")
It means before calling com.mumz.test.spring.aop.BookShelf.addBook method aroundAddAdvice method is called.
After
System.out.println("Book being added is : " + object); operation is completed . it will call your actual method addBook(). pjp.proceed() will call addBook() method.
Use JoinPoint with following advice types:
#Before, #After, #AfterReturning, #AfterThrowing
Use ProceedingJoinPoint with following advice type:
#Around
ProceedingJoinPoint is a JoinPoint with additional features.
ProceedingJoinPoint is used with #Around advice. #Around is very powerful advice that combines the features of rest of the Advice.
ProceedingJoinPoint::proceed is basically used to execute the original method.
Consider following example:
#Around("#annotation(com.annotations.ExecutionLoggerAround)")
public void executeLogger(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("Method execution starts at :: " + System.currentTimeMillis());
proceedingJoinPoint.proceed();
System.out.println("Method execution completes at :: " + System.currentTimeMillis());
}
#ExecutionLoggerAround
public void generateReport() {
System.out.println("Generating XLS report !!");
}
public #interface ExecutionLogger {
}
Now when you will call generateReport, Around advice will be executed. If you skip line proceedingJoinPoint.proceed(), the actual method will not be executed. You will see only those two println in the console.
PS: To understand better you need to know how AOP works. Spring creates proxy objects either using JDK proxy or CGLIB proxy. So its actually the proxied object that executes at runtime which use our method behind the scene.

Declaring an aspect on an aspect

I happen to have an #Aspect that declares a method that is intercepted by a pointcut of another aspect. The aspects are created with compile-time weaving and the container is instantiated using Spring.
I annotated my aspect with #Configurable to tell Spring that the component is being created outside the container. I happen to have a static reference to a Log object in this aspect too. To summarize, the code looks something like this
#Aspect
#Configurable
public class MyAspect {
private static final Log log = LogFactory.getClass(MyAspect.class);
// Autowired dependencies
// Pointcuts and advice
// Happens to be a pointcut of some other Advice
#Asynchronous
private Object someMethod(...) {
}
}
During AspectJ compilation, I do not see the message I expect, which looks something like this:
weaveinfo Join point 'method-call(java.lang.Object mypackage.someMethod(...))' in Type 'mypackage.MyAspect' (MyAspect.java:30) advised by around advice from 'anotherpackage.AsynchronousAspect' (from AsynchronousAspect.java))
As expected, the third-party advice is never invoked at this point. However, if I add a simple log entry to my advice, something like
log.debug("Join point invoked!");
Then the compilation happens correctly and all the aspects are wired (including my third party dependencies) and invoked correctly.
What does adding a log entry do to change my assumptions?
What you want to do is pretty straightforward and not dangerous at all if you know what you are doing. Please apologise that I am not a Spring user and that I prefer native AspectJ syntax to #AspectJ. This little sample runs just fine:
public class Application {
public static void main(String[] args) {
System.out.println("Hello world!");
someMethod();
}
private static void someMethod() {
System.out.println("Doing something ...");
}
}
public aspect FirstAspect {
void around() : execution(void *..main(..)) {
System.out.println(thisJoinPointStaticPart + ": " + someMethod("before", "main"));
proceed();
System.out.println(thisJoinPointStaticPart + ": " + someMethod("after", "main"));
}
private Object someMethod(String position, String methodName) {
return position + " " + methodName;
}
}
public aspect SecondAspect {
Object around() : execution(* *..someMethod(..)) {
System.out.println(thisJoinPointStaticPart + ": before someMethod");
Object result = proceed();
System.out.println(thisJoinPointStaticPart + ": after someMethod");
return result;
}
}
The result is as expected:
execution(Object FirstAspect.someMethod(String, String)): before someMethod
execution(Object FirstAspect.someMethod(String, String)): after someMethod
execution(void Application.main(String[])): before main
Hello world!
execution(void Application.someMethod()): before someMethod
Doing something ...
execution(void Application.someMethod()): after someMethod
execution(Object FirstAspect.someMethod(String, String)): before someMethod
execution(Object FirstAspect.someMethod(String, String)): after someMethod
execution(void Application.main(String[])): after main
If furthermore you are concerned with thhe order in which aspects are applied/executed, please use declare precedence.
If you experience problems with accessing e.g. private members, you need to use a privileged aspect.
Update: Changed usage of thisEnclosingJoinPointStaticPart to thisJoinPointStaticPart. That was just a copy & paste error. The result is the same on execution join points, but anyway the correction shows better the code's intent.

Categories