- Spring Essentials
- Shameer Kunjumohamed Hamidreza Sattari
- 1406字
- 2021-07-16 13:05:47
Dependency Injection
Dependency Injection is a specific form of Inversion of Control. It is a more formalized design pattern, whereby dependencies of an object are injected by an assembler. DI is generally performed in three major styles: constructor injection, property (setter) injection, or, sometimes, interface injection. IoC and DI are often used interchangeably.
DI offers several benefits, including effective decoupling of dependencies, cleaner code, and increased testability.
The Spring IoC container
The core Spring modules, spring-core
, spring-beans
, spring-context
, spring-context-support
, and spring-expression
, together make up the core container. The Spring IoC container is designed as an implementation of the following interfaces:
org.springframework.beans.factory.BeanFactory
org.springframework.context.ApplicationContext
The BeanFactory
interface provides the configuration framework and basic functionality, while ApplicationContext
, an extension of BeanFactory
, adds more enterprise-specific functionality, such as easier integration with Spring's AOP features, message resource handling (for internationalization), and event publication.
Spring provides several concrete implementations of ApplicationContext
out of the box for various contexts. The following table lists the most popular ones among them:
In Spring, objects managed by the IoC container are called beans. The IoC container handles the assembly and lifecycles of Spring beans. Beans are defined in the configuration metadata consumed by the container, which instantiates and assembles them in order to compose your application.
Configuration metadata
Spring supports three forms of configuration metadata to configure your beans:
- XML-based configuration metadata
- Annotation-based configuration metadata
- Java-based configuration metadata
The example code listing you saw earlier used XML-based configuration metadata. You can always mix and match different forms of metadata in a single application. For example, you may define the primary metadata to be a root XML file that combines a set of annotation-based metadata that in turn defines beans from different layers.
XML-based configuration metadata
The application-context.xml
file we saw in the previous Spring application sample is a very minimal example for XML-based configuration metadata. Beans are configured as <bean/>
elements inside a top-level <beans>
element.
Classes representing the service layer (core business logic, also known as Service classes), Data Access Objects (DAOs), managed web backing beans (such as Struts action instances and JSF managed beans), infrastructure objects (such as Hibernate session factories and JMS queues), and so forth, are excellent candidates for Spring beans. Fine-grained domain objects are not generally configured as Spring beans, because it is usually the responsibility of DAOs and the business logic to create and load domain objects—Hibernate entities are typical examples.
You can create a consolidated (root) ApplicationContext
XML file that imports other XML files representing various layers of the application:
<?xml version="1.0" encoding="UTF-8"?> <beans ...> <import resource="/xml-data-access-objects.xml"/> <import resource="/xml-services.xml"/> <import resource="/web-beans.xml"/> <import resource="/rest-endpoints.xml"/> ... <bean id="systemSettings" class="com...SystemSettings"> </beans>
Annotation-based configuration metadata
This method relies on bytecode metadata to wire up components instead of XML-based angle bracket declarations. Configuration of a bean is defined at the source level of the bean itself, in the form of annotations at class, field, or method levels.
Let's take a look at the simplest Spring bean configured by source-level annotation:
@Component("Greeter") public class GreetingServiceImpl implements GreetingService { Logger logger = LoggerFactory.getLogger(GreetingService.class); public void greet(String message) { logger.info("Greetings! " + message); } }
This is just an annotated version of the same GreetingServiceImpl
shown in the Your first Spring application section, where it was configured in the application-context.xml
file purely in XML form. In this preceding listing, the annotation @Component
makes it a Spring bean. Now, it doesn't require to be defined in XML, but you should instruct your ApplicationContext
to consider annotations, as given in the following code:
<context:component-scan base-package="com.springessentialsbook"/>
This code snippet in your application-context.xml
file forces ApplicationContext
to scan the entire application, including all its dependencies—even inside JAR files—for components annotated as Spring beans of various stereotypes, such as @Component
, @Service
, @Repository
, and @Controller
. In addition to component scanning, the ApplicationContext
looks for all the annotations in that bean at the class, property, constructor, and method levels (including setter methods) in order to inject dependencies and other behaviors into your beans at startup.
Beware, component scanning can be time consuming if you provide a broader package name to the base-package
attribute; it is advised to provide more specific package names to scan (for example, a set of comma-separated package names) so that you have more control. You can narrow down your component scanning even further using <context:include-filter/>
and <context:exclude-filter/>
.
Another simple instruction to enable annotation configuration is <context:annotation-config/>
. It simply looks for annotations on beans registered in the application context and will not detect the components, whereas if you use <context:component-scan/>
, it handles both component scanning and other annotations, which will be covered later in this chapter, so you do not need to explicitly declare <context:annotation-config/>
. So, the best method for annotation-based configuration is to use <context:annotation-config/>
.
XML-based versus annotation-based configuration
XML-based configuration has some advantages over its annotation-based counterpart. The biggest one is that all your bean definitions are in one place and not scattered in many classes or even JAR dependencies. XML allows you to split your metadata files and then combine them using <import/>
. Using XML, you can configure any class, including third-party ones such as Spring beans, and inject dependencies and other services into it, which is impossible in the case of annotation. Also, you can define the same class as multiple different beans, each with a different name, dependencies, configuration, and so on.
Annotation-based metadata too has some advantages over XML configuration. It is more concise and much easier to develop and maintain, as your annotation and DI are right inside your source code. All information about a class is in one place.
For bigger applications, the best option would be a mixed approach where the more reusable beans (libraries shared between multiple projects) and third-party components are configured in XML and those with a smaller scope are annotated.
Component stereotype annotations
Spring provides further component stereotypes for beans that represent various roles. The primary stereotype is @Component
, and all the others are its specializations for more specific use cases:
Custom stereotypes can be created by defining meta-annotations from scratch or combining existing annotations.
Java-based configuration metadata
Starting with Spring 3.0, you can configure Spring metadata purely inside Java classes, completely avoiding any XML configuration while enhancing annotation-based metadata. You annotate any Java class with @Configuration
annotation at the class level and have methods annotated as @Configuration
annotation on a factory method that instantiates an @Component
annotation, or any other specialized bean, to define your application context. Let's see a simple example:
@Configuration @ComponentScan(basePackages = "com.springessentialsbook") public class SpringJavaConfigurator { @Autowired private GreetingService greeter; @Autowired private BannerService banner; @Bean public BannerService createBanner() { return new BannerService(); } public BannerService getBanner() { return this.banner; } public void run() { this.banner.displayBanner(); this.greeter.greet("I am the Greeter Spring bean, configured with Java Configuration."); } }
In SpringJavaConfigurator.java
, the Java configuration class configures the Spring beans, replacing the application-context.xml
file. Your Spring application can directly depend on this Configuration
class for loading ApplicationContext
.
Typically, you use an AnnotationConfigApplication
instance for instantiating your application context:
ApplicationContext ctx = new AnnotationConfigApplicationContext( SpringJavaConfigurator.class); SpringJavaConfigurator app = ctx.getBean(SpringJavaConfigurator.class); app.run(); BannerService banner = ctx.getBean(BannerService.class); banner.displayBanner();
When @Configuration
classes are provided as the constructor argument, the @Configuration
class itself is registered as a bean definition and so are all declared @Bean
methods within the class. Spring will scan for the entire project and its dependencies for @Component
or its specializations (the other stereotypes listed previously), matching the argument values provided in @ComponentScan(basePackages = "…")
with all other relevant annotations and building the application context.
The advantage of JavaConfig metadata is that you have programmatic control over Spring configuration while separating out the entire DI and bean configuration into a separate Java class. Using JavaConfig, you eliminate the complexity of managing many XML files. You detect any configuration issues during development at the earliest, as JavaConfig fails during compilation itself, while in the case of XML, you will know about the configuration issues only on application startup.
JSR 330 standard annotations
Besides Spring-specific annotations, Spring supports JSR 330 standard annotations for DI, starting from Spring 3.0. You just need to include javax.inject
artifacts in your Maven or Gradle configuration.
JSR 330 standard annotations have the following equivalents in Spring:
While the default scope of Spring beans is singleton
, the JSR 330 default scope is like Spring's prototype
. However, for consistency, Spring treats JSR 330 annotated beans inside Spring as singleton
, unless declared prototype explicitly using @Scope("..")
.
JSR 330 has no equivalents for some Spring-based DI annotations, such as @Value
, @Required
, and @Lazy
. We will discuss more about bean scopes later in this chapter.
- iOS Game Programming Cookbook
- PyTorch Artificial Intelligence Fundamentals
- Julia Cookbook
- Responsive Web Design by Example
- Kotlin從基礎到實戰
- Java程序設計入門
- INSTANT Sinatra Starter
- Android玩家必備
- LabVIEW虛擬儀器入門與測控應用100例
- QGIS 2 Cookbook
- Android Development Tools for Eclipse
- Android移動應用開發項目教程
- Ionic3與CodePush初探:支持跨平臺與熱更新的App開發技術
- VMware vSphere Design Essentials
- 前端程序員面試算法寶典