2

When the aspect is enabled, the @Autowired bean in BeanB becomes a proxy, and the name field is null. Why? What should I do if I wish the original code to work properly?

Here is the code:

public class BeanA
{

    @Value("jami")
    //public String name;
    String name; //package visiblity


}

public class BeanB
{

    @Autowired
    private BeanA beanA;


    public void noLongerWorks()
    {
        System.out.println(beanA.name);
    }
}

public class Main
{

    public static void main(String[] args)
    {

        String[] configs = {"applicationContext.xml", "applicationContext-aop.xml"};//prints null
//      String[] configs = {"applicationContext.xml"};//prints jami
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);


        BeanB beanB = ctx.getBean(BeanB.class);
        beanB.noLongerWorks();

    }
}

---------- applicationContext.xml

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context.xsd">


    <context:annotation-config />
    <bean class="aop.pack1.BeanA" />
    <bean class="aop.pack1.BeanB" />


</beans>

------ applicationContext-aop.xml

<?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"
       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">

    <aop:aspectj-autoproxy />
    <bean class="aop.pack1.TestAspect" />


</beans>

@Aspect
public class TestAspect
{


    @Pointcut("target(aop.pack1.BeanA)")
    public void pointcut() {}


    @Before("pointcut()")
    public void advice()
    {
        System.err.println("___________advice__________");
    }
}

EDIT: I figured out one possible solution. But it does not seems very clean. Is there any elegant way to this? without making changes to existing code? The solution I found:

is to make all the fields in BeanA private, and only access them via getter setters.
This approach, however, requires a lot of modification of the original code (e.g. the BeanA class). 
du369
  • 821
  • 8
  • 22
  • Non-constant `public` fields are not considered elegant by most people. – Erwin Bolwidt Jan 04 '18 at 05:35
  • @ErwinBolwidt well, maybe you are right. I should make my point clearer by declaring the field as package visible which makes more sense. But the question is the same. The code example in the post is just some simplified version. The real situation I face is that I don't have much control over the said `BeanA` `BeanB` classes. – du369 Jan 04 '18 at 06:02

1 Answers1

1

You have already figured out the issue but, I wanted to share this article I came across that lists what Spring AOP can and cannot do.

In your case

  1. Since it uses proxy-based AOP, only method-level advising is supported; it does not support field-level interception So join-points can be at method level not at field level in a class.

  2. Only methods with public visibility will be advised: Methods with private, protected, or default visibility will not be advised.

Just a recommendation and I think it's also a good OOP practice to create fields with private or protected visibility and provide appropriate getters and setters to access them.

These SO Q/A might be useful

Spring AOP - get old field value before calling the setter

spring singleton bean fields are not populated

Spring AOP CGLIB proxy's field is null

Community
  • 1
  • 1
Raf
  • 7,505
  • 1
  • 42
  • 59