Skip to content

@Bean JavaConfiguration

Yash edited this page Aug 28, 2018 · 2 revisions

Bean: is an object, which is created, managed and destroyed in Spring Container. We can inject an object into the Spring Container through the metadata(either xml or annotation), which is called inversion of control.

From Stack Post

Bean Bean Life Cycle

public class Message {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
}

XmlWebApplicationContext

<web-app>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      /WEB-INF/Spring-servlet.xml
    </param-value>
    <param-value>classpath:/webApplicationContext/*.xml</param-value>
  </context-param>

  <!-- http://docs.spring.io/spring/docs/2.5.6/reference/mvc.html -->
  <!-- @Autowire or load time beans-object creation, we need to use this listener. 
    this listener will activate when the bean object is creating and the required 
    values will supply to it. start up a Spring root application context via 
    its ContextLoaderListener, and access it via its ServletContext attribute -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <servlet>
    <servlet-name>Spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <!-- Try calling your controllers with a different extension (*.do for example 
    - where * is the WildCard). *.do matches anything that ends in .do, for example, 
    /foo.do, /foo/bar.do. *.do | / -->
  <servlet-mapping>
    <servlet-name>Spring</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

<!-- applicationcontext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  
  <bean id="beanXMLID" class="com.github.pojo.Message">
    <property name="message" value="Hello World!"/>
  </bean>
</beans>
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext ctx = 
         new ClassPathXmlApplicationContext("applicationContext.xml");
      // instantiate our bean object from the application context
      Message obj = (Message) ctx.getBean("beanXMLID");
      obj.getMessage();
   }
}

Web MVC Application

<web-app>
    <!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
        instead of the default XmlWebApplicationContext -->
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>

    <!-- Configuration locations must consist of one or more comma- or space-delimited
        fully-qualified @Configuration classes. Fully-qualified packages may also be
        specified for component-scanning -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.acme.AppConfig</param-value>
    </context-param>

    <!-- Bootstrap the root application context as usual using ContextLoaderListener -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- Declare a Spring MVC DispatcherServlet as usual -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
            instead of the default XmlWebApplicationContext -->
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>
                org.springframework.web.context.support.AnnotationConfigWebApplicationContext
            </param-value>
        </init-param>
        <!-- Again, config locations must consist of one or more comma- or space-delimited
            and fully-qualified @Configuration classes -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.acme.web.MvcConfig</param-value>
        </init-param>
    </servlet>

    <!-- map all requests for /app/* to the dispatcher servlet -->
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>
</web-app>

Stand Alone Application « The Message bean is decorated with the @Component annotation. Such classes are auto-detected by Spring. With the @ComponentScan annotation we tell Spring where to look for components.

@Component
public class Message { ... }

@ComponentScan(basePackages = "com.github")
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext ctx = 
         new AnnotationConfigApplicationContext(MessageConfig.class);
   
      Message obj = ctx.getBean(Message.class);
      obj.setMessage("Hello World!");
      obj.getMessage();
   }
}

@Configuration
public class MessageConfig {
   @Bean 
   public Message message(){
      return new Message();
   }
}
public class MyWebAppInitializer implements WebApplicationInitializer {

 @Override
 public void onStartup(ServletContext container) {
  // Create the 'root' Spring application context
  AnnotationConfigWebApplicationContext rootContext =
                       new AnnotationConfigWebApplicationContext();
  rootContext.register(WebSpringConfig.class);

  // Manage the lifecycle of the root application context
  container.addListener(new ContextLoaderListener(rootContext));

  // Create the dispatcher servlet's Spring application context
  AnnotationConfigWebApplicationContext dispatcherContext =
                     new AnnotationConfigWebApplicationContext();
  dispatcherContext.register(DispatcherConfig.class);

  // Register and map the dispatcher servlet
  ServletRegistration.Dynamic dispatcher =
    container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");
  }
}

@Bean is a method-level annotation and a direct analog of the XML element. The annotation supports most of the attributes offered by , such as: init-method, destroy-method, autowiring, lazy-init, dependency-check, depends-on and scope.

Declaring a bean

To declare a bean, simply annotate a method with the @Bean annotation. When JavaConfig encounters such a method, it will execute that method and register the return value as a bean within a BeanFactory. By default, the bean name will be the same as the method name (see bean naming for details on how to customize this behavior). The following is a simple example of a @Bean method declaration:

@Configuration
public class AppConfig {
    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }
}

For comparison sake, the configuration above is exactly equivalent to the following Spring XML:

<beans>
    <bean name="transferService" class="com.acme.TransferServiceImpl"/>
</beans>

Bean Names

While a name attribute is available, the default strategy fordetermining the name of a bean is to use the name of the @Bean method.This is convenient and intuitive, but if explicit naming is desired, the name attribute (or its alias value) may be used. Also notethat name accepts an array of Strings, allowing for multiple names(i.e. a primary bean name plus one or more aliases) for a single bean.

     @Bean({"b1", "b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
     public MyBean myBean() {
         // instantiate and configure MyBean obj
         return obj;
     }

@Bean Methods in @Configuration Classes

Typically, @Bean methods are declared within @Configuration classes. In this case, bean methods may reference other @Bean methods in thesame class by calling them directly. This ensures that references between beansare strongly typed and navigable. Such so-called 'inter-bean references' areguaranteed to respect scoping and AOP semantics, just like getBean() lookupswould. These are the semantics known from the original 'Spring JavaConfig' projectwhich require CGLIB subclassing of each such configuration class at runtime. As aconsequence, @Configuration classes and their factory methods must not bemarked as final or private in this mode. For example:

 @Configuration
 public class AppConfig {

     @Bean
     public FooService fooService() {
         return new FooService(fooRepository());
     }

     @Bean
     public FooRepository fooRepository() {
         return new JdbcFooRepository(dataSource());
     }

     // ...
 }

@Bean Lite Mode

@Bean methods may also be declared within classes that are not-annotated with @Configuration. For example, bean methods may be declaredin a @Component class or even in a plain old class. In such cases,a @Bean method will get processed in a so-called 'lite' mode.

Bean methods in lite mode will be treated as plain factorymethods by the container (similar to factory-method declarationsin XML), with scoping and lifecycle callbacks properly applied. The containingclass remains unmodified in this case, and there are no unusual constraints forthe containing class or the factory methods.

In contrast to the semantics for bean methods in @Configuration classes, 'inter-bean references' are not supported in lite mode. Instead,when one @Bean-method invokes another @Bean-method in litemode, the invocation is a standard Java method invocation; Spring does not interceptthe invocation via a CGLIB proxy. This is analogous to inter-@Transactionalmethod calls where in proxy mode, Spring does not intercept the invocation — Spring does so only in AspectJ mode.

For example:

 @Component
 public class Calculator {
     public int sum(int a, int b) {
         return a+b;
     }

     @Bean
     public MyBean myBean() {
         return new MyBean();
     }
 }

BeanFactoryPostProcessor-returning @Bean methods

Special consideration must be taken for @Bean methods that return Spring BeanFactoryPostProcessor(BFPP) types. Because BFPP objects must be instantiated very early in thecontainer lifecycle, they can interfere with processing of annotations such as @Autowired, @Value, and @PostConstruct within @Configuration classes. To avoid theselifecycle issues, mark BFPP-returning @Bean methods as static. For example:

     @Bean
     public static PropertySourcesPlaceholderConfigurer pspc() {
         // instantiate, configure and return pspc ...
     }

Example: @Value, @PostConstruct Properties

@Configuration
public class TomcatHttpAndHttpsConfig {
    
    
    @Value("${app.http.port:8080}")
    private int httpPort;
    @Value("${app.https.port:8443}")
    private int httpsPort;
    
    @Value("${app.ssl.redirect:false}")
    private boolean sslRedirect;
    
    @Value("${app.domain}")
    private String applicationDomain;
    @PostConstruct
    public void print() {
        System.out.println("============");
        System.out.println("Application Domain Name : "+ applicationDomain);
        System.out.println("SSL Redirect            : "+ sslRedirect);
        System.out.println("============");
    }
    
    @Bean
    public ServletWebServerFactory servletContainer(){
        // embedded.tomcat.TomcatWebServer «  Tomcat started on port(s): 8443 (https) 8080 (http) with context path ''
        if( sslRedirect ) {
            return this.tomcatRedirectHttpToHttpsConfig();
        } else {
            return this.tomcatHttpToHttpsConfig();
        }
    }

    /* 
    * https://localhost:8443/ - Response status 200
    * http://localhost:8080/  - Response status 200
    */
    private TomcatServletWebServerFactory tomcatHttpToHttpsConfig() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addAdditionalTomcatConnectors(initiateHttpConnector());
        return tomcat;
    }
    
    /* 
    * IN-Request 8080 - Redirect Request with status code 302 - In-Request 8443
    * https://localhost:8443/ - Response status 200
    * http://localhost:8080/  - Response status 302 - [ReDirect request with 8443] - status 200 
    */
    private TomcatServletWebServerFactory tomcatRedirectHttpToHttpsConfig() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(redirectConnector());
        
        return tomcat;
    }
    
    private Connector initiateHttpConnector(){
        Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
        connector.setScheme("http");
        connector.setPort( this.httpPort );
        connector.setSecure(false);
        return connector;
    }
    
    private Connector redirectConnector(){
        Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
        connector.setScheme("http");
        connector.setPort( this.httpPort );
        connector.setSecure(false);
        connector.setRedirectPort( this.httpsPort );
        return connector;
    }
}

Clone this wiki locally