Announcement Announcement Module
Collapse
No announcement yet.
First method works the second doesn't. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • First method works the second doesn't.

    Hi there,

    I have a very weird and irritating problem. I'll try to explain it as clear as possible. The project I was working on was a little more complex but I've recreated the same problem with a very simple example.

    I have 4 different classes:
    • Starter: This class extends from Thread and calls Runner.startRunning() as soon as it has been started.
    • Runner: The runner starts to run for a distance of 150 (let's say miles). Every step() returns a random int that gets added to the total distance.
    • Logger: The logger tries to log every step the Runner takes. So every time the Runner.step() method is executed.
    • Main: Just a main method to start all the running via the Thread.

      AOP looked the best way to solve the logging problem so I started creating a config file. But apparently it isn't possible to make a pointcut of the Runner.step() method! But a pointcut for the Runner.startRunning() method works perfectly. See example code below or eclipse project on this link.

    Simple class for the Threading
    Code:
    package main;
    
    public class Starter extends Thread{
    
    	private Runner runner;
    	
    	public Starter(Runner runner) {
    		this.runner = runner;
    	}
    
    	@Override
    	public void run() {
    		this.runner.startRunning();
    	}
    	
    	
    }
    The class with the actual logic
    Code:
    package main;
    
    import java.util.Random;
    
    public class Runner {
    
    	public void startRunning() {
    		System.out.println("Started Running");
    		int distance = 0;
    		
    		do {
    			distance += step();
    		} while (distance < 150);
    		
    	}
    	
    	public int step() {
    		return new Random().nextInt(5);
    	}
    }
    The logger:
    Code:
    package main;
    
    public class Logger {
    	public Logger(){}
    	
    	public void after() {
    		System.out.println("Took a step");
    	}
    }
    The config:
    HTML Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans 
    	xmlns="http://www.springframework.org/schema/beans"
     	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     	xmlns:aop="http://www.springframework.org/schema/aop"
     	xmlns:util="http://www.springframework.org/schema/util"
     	xsi:schemaLocation="http://www.springframework.org/schema/beans 
     						http://www.springframework.org/schema/beans/spring-beans.xsd
     						http://www.springframework.org/schema/aop
         					http://www.springframework.org/schema/aop/spring-aop.xsd
         					http://www.springframework.org/schema/util 
         					http://www.springframework.org/schema/util/spring-util-2.0.xsd"> 	
    		
    	
    	
    	<bean id="Runner" class="main.Runner"/>
    	
    	<bean id="Logger" class="main.Logger"/>
    	
    	<aop:config>
    		<aop:aspect ref="Logger">
    			<aop:pointcut expression="execution (* main.Runner.step(..))" id="method-to-log"/>
    			<aop:after method="after" pointcut-ref="method-to-log" />
    		</aop:aspect>
    	</aop:config>
    </beans>
    The main class:
    Code:
    package main;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Main {
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		ApplicationContext context = new ClassPathXmlApplicationContext("spring-runner.xml");
    		Runner runner = (Runner) context.getBean("Runner");
    		Starter starter = new Starter(runner);
    		starter.start();
    	}
    
    }
    Thanks in advance!

  • #2
    Hi,

    AOP doesn't work on the step() method because you don't call this method externally but call it only inside the class itself. Spring AOP is proxy-based so internal method calls can't be advised. You need tu set up full-blown AspectJ for that, or change your application logic so that the method step() is called from another class.

    Aside from that, there are also many other problems with the code you submitted:

    1) In a Spring application, you should never spawn threads the "Java way" but use the @Async annotation which is the "Spring way" to accomplish just the same. By doing this, you have the guarantee that Spring's additional features (like AOP) will work as expected. By spawning threads yourself, you are working against the framework so there is no guarantee that everything will work as expected;

    2) Another way in which you go against the framework, is that you don't use dependency injection, which is the foundation of Spring. If you use spring correctly, the "new" java keyword should be banned. You should inject your runner inside your starter and, in the main class, you should get directly the starter class;

    3) Also, respect naming conventions. Ids of Spring beans should start lowercase.

    All this urges me to suggest a more careful study of the Spring documentation.

    Comment

    Working...
    X