Spring java-based Container Configuration (ii)

Source: Internet
Author: User

# # # assembly java-based Configuration


* Use @import annotations


Similar to adding a modular configuration using the ' <import> ' element in the spring XML file, @Import annotations allow you to load @bean definitions from other configuration classes:
"' Java
@Configuration
public class Configa {


@Bean
Public a A () {
return new A ();
}


}


@Configuration
@Import (Configa.class)
public class CONFIGB {


@Bean
Public b b () {
return new B ();
}


}
```
Now, when instantiating the context, you only need to explicitly specify CONFIGB, without having to provide both Configa.class and Configb.class:
"' Java
public static void Main (string[] args) {
ApplicationContext CTX = new Annotationconfigapplicationcontext (configb.class);


Now both beans A and B would be available ...
A = Ctx.getbean (A.class);
b b = Ctx.getbean (B.class);
}
```
This simplifies the initialization of the container because only one class needs to be processed, rather than having the developer remember a large number of @configuration classes during construction.


* Import @bean Dependency Injection


The above example can work, but it's too simple. In most real-world scenarios, beans relies on another bean that spans the configuration class. When using XML, this is not a problem, because it does not involve compilation, where one bean only needs to declare ' ref= ' Somebean "', leaving the rest to spring to be processed during container initialization. Of course, when using the @configuration class, the Java compiler has some limitations on configuration patterns, and references to other beans must be legitimate Java syntax.


Fortunately, it is easy to solve the problem. As we [have discussed] (http://docs.spring.io/spring/docs/4.2.0.RC1/spring-framework-reference/htmlsingle/# beans-java-dependencies), @Bean can have any number of parameters that describe bean dependencies. Let's explore a more realistic scenario where we'll use some of the @configuration classes that depend on each other:
"' Java
@Configuration
public class ServiceConfig {


@Bean
Public Transferservice Transferservice (accountrepository accountrepository) {
return new Transferserviceimpl (accountrepository);
}


}


@Configuration
public class Repositoryconfig {


@Bean
Public accountrepository accountrepository (DataSource DataSource) {
return new Jdbcaccountrepository (DataSource);
}


}


@Configuration
@Import ({serviceconfig.class, repositoryconfig.class})
public class Systemtestconfig {


@Bean
Public DataSource DataSource () {
return new DataSource
}


}


public static void Main (string[] args) {
ApplicationContext CTX = new Annotationconfigapplicationcontext (systemtestconfig.class);
Everything wires up across configuration classes ...
Transferservice Transferservice = Ctx.getbean (Transferservice.class);
Transferservice.transfer (100.00, "A123", "C456");
}
```
Here's another way to achieve the same effect. Remember, @Configuration is essentially just another bean-in the container, which means they can take full advantage of @autowired injection metadata like other beans.
* * NOTE: * * Ensure that all injected in this way is of a simple type. @Configuration classes are handled quite early when the container is initialized, forcing the injection of dependency in this way can lead to unexpected premature initialization of the problem. Use the parameter-based injection in the above example whenever possible.


"' Java
@Configuration
public class ServiceConfig {


@Autowired
Private Accountrepository accountrepository;


@Bean
Public Transferservice Transferservice () {
return new Transferserviceimpl (accountrepository);
}


}


@Configuration
public class Repositoryconfig {


@Autowired
Private DataSource DataSource;


@Bean
Public Accountrepository accountrepository () {
return new Jdbcaccountrepository (DataSource);
}


}


@Configuration
@Import ({serviceconfig.class, repositoryconfig.class})
public class Systemtestconfig {


@Bean
Public DataSource DataSource () {
return new DataSource
}


}


public static void Main (string[] args) {
ApplicationContext CTX = new Annotationconfigapplicationcontext (systemtestconfig.class);
Everything wires up across configuration classes ...
Transferservice Transferservice = Ctx.getbean (Transferservice.class);
Transferservice.transfer (100.00, "A123", "C456");
}
```
In the example above, working with @autowired is good and provides the modularity you want, but it's important to specify exactly where the claims for the automatically injected bean definition are still somewhat blurred. For example, if a developer is viewing serviceconfig, how do you know exactly where the ' @Autowired accountrepository ' bean is declared? It's not clear in the code, but sometimes it's OK. Remember that [Spring tool Suite] (https://spring.io/tools/sts) provides a tool for rendering diagrams that show how Spring beans are connected-which is probably what you need. At the same time, your Java IDE can easily find all the beans that declare and use the Accountrepository type, and quickly show you the @bean method location that returns that type.


If you cannot accept this ambiguity and want to be able to navigate from one @configuration class to another in your IDE, consider injecting the configuration class itself:
"' Java
@Configuration
public class ServiceConfig {


@Autowired
Private Repositoryconfig Repositoryconfig;


@Bean
Public Transferservice Transferservice () {
Navigate ' through ' the Config class to the @Bean method!
return new Transferserviceimpl (Repositoryconfig.accountrepository ());
}


}
```
In the solution above, we can know exactly where accountrepository is defined. However, ServiceConfig is now tightly coupled to repositoryconfig. That's the tradeoff. Tight coupling can be mitigated to some extent by using @configuration classes based on interfaces or abstract classes. Consider the following:
"' Java
@Configuration
public class ServiceConfig {


@Autowired
Private Repositoryconfig Repositoryconfig;


@Bean
Public Transferservice Transferservice () {
return new Transferserviceimpl (Repositoryconfig.accountrepository ());
}
}


@Configuration
Public interface Repositoryconfig {


@Bean
Accountrepository accountrepository ();


}


@Configuration
public class Defaultrepositoryconfig implements Repositoryconfig {


@Bean
Public Accountrepository accountrepository () {
return new Jdbcaccountrepository (...);
}


}


@Configuration
@Import ({serviceconfig.class, defaultrepositoryconfig.class})//Import the concrete config!
public class Systemtestconfig {


@Bean
Public DataSource DataSource () {
Return DataSource
}


}


public static void Main (string[] args) {
ApplicationContext CTX = new Annotationconfigapplicationcontext (systemtestconfig.class);
Transferservice Transferservice = Ctx.getbean (Transferservice.class);
Transferservice.transfer (100.00, "A123", "C456");
}
```
Now, ServiceConfig is loosely coupled with the specific Defaultrepositoryconfig class, and the embedded IDE tool is still useful: it is easy for developers to get the type hierarchy of Repositoryconfig implementations. In this way, navigating @configuration and their dependencies becomes indistinguishable from the usual handling of interface-based code navigation.


* Conditional inclusion of @configuration class or @beans


It is often useful to conditionally disable a complete @configuration class based on any system state, or even a separate @bean method. A common example is when a specific profile is enabled in spring environment, the beans is activated using the @profile annotation.


@Profile annotations actually implement a very flexible annotation: [@Conditional] (http://docs.spring.io/spring/docs/current/javadoc-api/org/ springframework/context/annotation/conditional.html). @Conditional annotations imply that the specified ' org.springframework.context.annotation.Condition ' implementation must be consulted prior to registering @bean.


The condition interface's implementation simply provides a ' matches (...?) that returns True or false. Method For example, the following is the condition implementation of the @profile annotation:
"' Java
@Override
Public Boolean matches (Conditioncontext context, annotatedtypemetadata metadata) {
if (context.getenvironment () = null) {
Read the @Profile annotation attributes
multivaluemap<string, object> attrs = Metadata.getallannotationattributes (Profile.class.getName ());
if (attrs! = null) {
For (Object value:attrs.get ("value")) {
if (Context.getenvironment (). Acceptsprofiles (((string[]) value)) {
return true;
}
}
return false;
}
}
return true;
}
```
Specific references [@Conditional Javadocs] (http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ annotation/conditional.html).


* Combined with Java and XML configuration


Spring @Configuration class support is not intended to replace the spring XML with 100%. Some facilities, such as the spring XML namespace, are still the perfect way to configure containers. In case XML is convenient or necessary, you have a choice: to instantiate a container in an "XML-centric" way, such as Classpathxmlapplicationcontext, Or use Annotationconfigapplicationcontext as a "Java-centric" approach and use @importresource annotations to import the required XML.


* Use the @configuration class with "XML as the center"


Starting the spring container from XML, including the @configuration class in ad hoc mode, can be a more optional approach. For example, in a large code base that already exists that uses spring XML, it is very easy to follow the on-demand principle of creating @configuration and including them from existing XML files. Below you will find options for using the @configuration class in such an "XML-centric" solution.


Remember that the @configuration class is essentially a bean definition in a container. In the following example, we create a @configuration class named AppConfig and include it as a ' <bean/> ' definition in ' system-test-config.xml '. Because ' <context:annotation-config/> ' is turned on, the container will recognize @configuration annotations and correctly handle the @bean method declared in AppConfig.
"' Java
@Configuration
public class AppConfig {


@Autowired
Private DataSource DataSource;


@Bean
Public Accountrepository accountrepository () {
return new Jdbcaccountrepository (DataSource);
}


@Bean
Public Transferservice Transferservice () {
return new Transferservice (Accountrepository ());
}


}
```
System-test-config.xml as follows:
"' XML
<beans>
<!--enable processing of annotations such as @Autowired and @Configuration-
<context:annotation-config/>
<context:property-placeholder location= "Classpath:/com/acme/jdbc.properties"/>


<bean class= "Com.acme.AppConfig"/>


<bean class= "Org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name= "url" value= "${jdbc.url}"/>
<property name= "username" value= "${jdbc.username}"/>
<property name= "Password" value= "${jdbc.password}"/>
</bean>
</beans>
```
Jdbc.properties as follows:
"Properties"
Jdbc.properties
Jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
Jdbc.username=sa
jdbc.password=
```
The main method is as follows:
"' Java
public static void Main (string[] args) {
ApplicationContext CTX = new Classpathxmlapplicationcontext ("Classpath:/com/acme/system-test-config.xml");
Transferservice Transferservice = Ctx.getbean (Transferservice.class);
// ...
}
```
* * NOTE: * * in the ' system-test-config.xml ' above, ' appconfig<bean/> ' does not declare an ' ID ' element. If there is no bean referencing it, it is not necessary to specify the ' ID ' element, otherwise the bean will be fetched from the container by name (the name corresponds to the ID declared in the bean definition). DataSource is the same-it is simply injected via type (autowired by type), so you do not need to explicitly assign a bean ID.


Since @configuration is annotated by @component (annotated, very awkward), the class that is @configuration annotated automatically becomes a candidate for component scanning (component scanning). Also using the above scenario, we can redefine ' system-test-config.xml ' to take full advantage of component scanning. Note In this example, we do not need to explicitly declare ' <context:annotation-config/> ' because ' <context:component-scan/> ' has the same functionality enabled.


System-test-config.xml as follows:
"' XML
<beans>
<!--picks up and registers AppConfig as a bean definition---
<context:component-scan base-package= "Com.acme"/>
<context:property-placeholder location= "Classpath:/com/acme/jdbc.properties"/>


<bean class= "Org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name= "url" value= "${jdbc.url}"/>
<property name= "username" value= "${jdbc.username}"/>
<property name= "Password" value= "${jdbc.password}"/>
</bean>
</beans>
```
* Import XML using @importresourcedaoru in @configuration "class-centric" scenario


In applications that use the @configuration class as the primary mechanism for configuring containers, there is still a need for XML. In those scenarios, you can use @importresource and define the XML that you want. Doing so allows you to configure the container in a "Java-centric" manner, preserving a minimal amount of XML.
"' Java
@Configuration
@ImportResource ("Classpath:/com/acme/properties-config.xml")
public class AppConfig {


@Value ("${jdbc.url}")
Private String URL;


@Value ("${jdbc.username}")
Private String username;


@Value ("${jdbc.password}")
private String password;


@Bean
Public DataSource DataSource () {
return new Drivermanagerdatasource (URL, username, password);
}


}
```
Properties-config.xml as follows:
"' XML
<beans>
<context:property-placeholder location= "Classpath:/com/acme/jdbc.properties"/>
</beans>
```
Jdbc.properties as follows:
"Properties"
Jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
Jdbc.username=sa
jdbc.password=
```
The main method is as follows:
"' Java
public static void Main (string[] args) {
ApplicationContext CTX = new Annotationconfigapplicationcontext (appconfig.class);
Transferservice Transferservice = Ctx.getbean (Transferservice.class);
// ...
}
```

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Spring java-based Container Configuration (ii)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.