Search code examples
springspring-annotations

Spring pure annotation with autowired


I am trying to do a full annotations (no xml) implementation of Spring. The autowired members are not being populated. From my research, there are 3 things to do:

  • Set up a config file that manages the bean

  • Use @Autowired to get the bean to the file

  • Instantiate an application context to get the ball rolling

It is difficult to find a complete example of this which uses annotations only, so I don't have much to reference. Most examples use at least some xml.

There is no error message, so I don't have any idea where the problem is. The value is just null. Here are my files:

Trivial.java

public class Trivial {

    public TrivialBean trivialBean;

    @Autowired
    public void setTrivialBean(TrivialBean trivialBean) {
        this.trivialBean = trivialBean;
    }

    public static void main(String...args) {

        ApplicationContext context
                = new AnnotationConfigApplicationContext(
                TrivialConfig.class);

        new Trivial().go();
    }

    private void go() {

        System.out.println("trivialBean: " + trivialBean);
    }
}

TrivialBean.java

public class TrivialBean {

    public String foo = "TEST TEST TEST";

    @Override
    public String toString() {
        return foo;
    }
}

TrivialConfig.java

@Configuration
public class TrivialConfig {

    @Bean
    public TrivialBean trivialBean() {
        return new TrivialBean();
    }
}

I would expect this to output trivialBean: TEST TEST TEST, but is just outputs trivialBean: null


Solution

  • Regular autowiring in annotation-based container configuration

    In order for autowiring to work, the lifecycle of the instance of Trivial has to be managed by the Spring container.

    Example

    TrivialBean.java is the same

    public class TrivialBean {
    
        public String foo = "TEST TEST TEST";
    
        @Override
        public String toString() {
            return foo;
        }
    }
    

    TrivialConfig.java

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class TrivialConfig {
    
        @Bean
        public TrivialBean trivialBean() {
            return new TrivialBean();
        }
    
        @Bean
        public Trivial trivial() {
            return new Trivial();
        }
    }
    

    Trivial.java

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class Trivial {
    
        public TrivialBean trivialBean;
    
        @Autowired
        public void setTrivialBean(TrivialBean trivialBean) {
            this.trivialBean = trivialBean;
        }
    
        public static void main(String... args) {
    
            ApplicationContext context = new AnnotationConfigApplicationContext(TrivialConfig.class);
            Trivial trivial = context.getBean(Trivial.class);
            trivial.go();
        }
    
        private void go() {
            System.out.println("trivialBean: " + trivialBean);
        }
    }
    

    Output

    trivialBean: TEST TEST TEST
    

    Please consult Spring documentation for more information on Annotation-based container configuration.


    AspectJ compile-time weaving and @Configurable

    It is possible to autowire TrivialBean instance into Trivial instance created by new.

    spring-aspects.jar contains an annotation-driven aspect that allows dependency injection for objects created outside of the control of the container. However, it should not be used in new Spring-based projects. It is intended to be used for legacy projects, where for some reason some instances are created outside of the Spring container.

    Example for Spring 4.2.0 (the latest at the moment), AspectJ 1.8.6 (the latest at the moment), Maven and Java 1.8.

    Additional dependencies on spring-aspects and aspectjrt

       <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.6</version>
        </dependency>
    

    Compile time weaving via AspectJ Maven plugin

    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.7</version>
        <configuration>
            <complianceLevel>1.8</complianceLevel>
                <encoding>UTF-8</encoding>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
                <Xlint>warning</Xlint>
          </configuration>
          <executions>
              <execution>
                  <goals>
                      <goal>compile</goal>
                      <goal>test-compile</goal>
                  </goals>
              </execution>
          </executions>
    </plugin>
    

    TrivialBean.java is the same

    public class TrivialBean {
    
        public String foo = "TEST TEST TEST";
    
        @Override
        public String toString() {
            return foo;
        }
    }
    

    TrivialConfig.java

    @EnableSpringConfigured is analogous to <context:spring-configured>. It signals the current application context to apply dependency injection to classes that are instantiated outside of the Spring bean factory.

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.aspectj.EnableSpringConfigured;
    
    @Configuration
    @EnableSpringConfigured
    public class TrivialConfig {
    
        @Bean
        public TrivialBean trivialBean() {
            return new TrivialBean();
        }
    }
    

    Trivial.java

    @Configurable applies Spring-driven configuration to Trivial

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Configurable;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    @Configurable
    public class Trivial {
    
        public TrivialBean trivialBean;
    
        @Autowired
        public void setTrivialBean(TrivialBean trivialBean) {
            this.trivialBean = trivialBean;
        }
    
        public static void main(String... args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(TrivialConfig.class);
            Trivial trivial = new Trivial();
            trivial.go();
        }
    
        private void go() {
            System.out.println("trivialBean: " + trivialBean);
        }
    }
    

    Output

    trivialBean: TEST TEST TEST
    

    It works! Please consult Spring documentation for more information on AspectJ and @Configurable.