Dependency Injection (DI) is at the heart of Spring. It refers to plugging in references at runtime between many different objects, either through a constructor, setter, or even directly to a field using runtime reflection. This enables IOC (Inversion of Control) where one class can use an instance of another class without knowing any details about how that object was constructed or its exact implementation class.
Spring’s design allows the use of POJOs (Plain Old Java Objects). In other words, you don’t need to implement a specific interface or extend a class in order to use Spring’s DI. An instance of a class configured by Spring is called a Spring Bean, or sometimes just bean for short.
Decoupling
For example, you can annotate a setter or field with @Autowired on a Spring Bean , and Spring will find the class at runtime that best matches that field or setter. By default, it will search for the class matching the type. If it can’t find a matching bean or there is more than one possible match (after considering any @Qualifier annotation and the name), Spring will throw an Exception and fail to start.
You should use interfaces to further decouple different classes. This way different components can be tested independently and not rely on the implementation of other components. Tight coupling in enterprise applications leads to brittle code and makes it very hard to make changes without breaking anything.
You can use @Qualifier to specify a specific name of an instance to help @Autowired find the right instance when many instances of the same class or interface might exist. We will show an example of this in the next section.
Configuration
Beans can be configured in one of three ways: XML, a configuration Java class annotated with @Configuration and methods annotated with @Bean, or on the Bean class itself with an annotation such as @Component . The most recommended way is using one or more Java configuration classes.
This configuration creates one bean instance of the Configuration class itself and one bean instance named myService of class MyActualService which implements the MyService interface (from the method annotated with @Bean).
The default scope is “singleton,” meaning one instance or “singleton” of the class will exist for the application. Other scopes such as “application,” “request,” and “session” exist in a web application. The “prototype” scope means a new instance will be created of the bean every time it’s requested. A bean’s scope can be changed using the @Scope annotation. For example, @Scope("prototype") @Bean public MyService myService() {...}
Configuration.java
By default Spring uses the method name as the Bean’s name. So the preceding example creates a Bean named “myService” and a Bean named “service2”. You can override it by supplying a value to the @Bean annotation (like @Bean("myname")).
In this way, even if multiple beans exist that implement MyService, Spring will know to choose the one named “myService”.
You can also configure a bean to have multiple names. For example, using @Bean(name={"myname1", "myname2"}) would register the same bean under two names, myname1 and myname2.
Application Context
The ApplicationContext is the interface that directly exposes all of the beans configured by Spring.
It has a different concrete class depending on the type of application. For example, a web application will have an implementation of WebApplicationContext.
Component Scanning
You can use component scanning in Spring to scan classes for certain annotations on the class declaration. Those annotations are @Component, @Controller, @Service, and @Repository (and @Configuration). If they are found, Spring will initialize that POJO as a Spring Bean.
Configuration.java
In these examples, the “com.example” package and all of its subpackages will be scanned for Spring annotations to create beans. Be careful not to scan too many classes as this will slow down initialization time.
Import
You can import other configuration files using @Import. Using @ComponentScan can also be used to scan for configuration classes (classes marked with @Configuration).
This would import the WebConfig and ServiceConfig configuration classes and the dao.xml Spring configuration file (see the next chapter for more about XML).
Laziness
Beans are created eagerly by default – which means Spring will instantiate them and wire them up at start-up time. This makes it faster to find any potential problems. You can make a Bean load lazily using the @Lazy annotation if you don’t want it to load until necessary (when requested for using the ApplicationContext.getBean(String) method or requested by, e.g., autowiring).
Shut Down the ApplicationContext
App.java
This way, Spring will gracefully shut down when the application exits.
BeanFactoryPostProcessors
The BeanFactoryPostProcessor interface can be implemented to change bean configurations before the beans are created (of all other beans). This can be useful for adding custom configuration, for example (although Spring handles most useful cases by itself). The BeanFactoryPostProcessor interface has one method to define, postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory). Spring automatically detects beans that implement this interface.
BeanPostProcessors
An ApplicationContext also automatically detects any beans that are defined in the configuration metadata it receives that implement the BeanPostProcessor interface. These beans are special because they are created at the same time as the ApplicationContext and before any other beans so they can process other bean definitions.
Spring AOP, which we will cover later, is implemented using the BeanPostProcessor interface. It can replace each bean with a proxy of that bean.
Init and Destroy Methods
You can enable JSR-250 annotations like @PostConstruct and @PreDestroy using the CommonAnnotationBeanPostProcessor in Spring. It’s activated by component scanning but otherwise can be activated directly in your Spring configuration.
An alternative is to use Spring’s built-in configuration. For example, the Bean annotation, @Bean(initMethod = "up", destroyMethod = "down") would cause Spring to call “up” after initializing the class and injecting all dependencies and “down” right before destroying it.
Properties
By default, Spring Boot will load properties from your classpath from a file named application.properties (for standard properties) or application.yml (for YAML-formatted properties).
Additional properties can be loaded into the environment using the @PropertySource annotation.
AppConfig.java
This would inject “Bob” into the beanName field previously mentioned.
Environment
String getProperty(String key) – Gets the value for a given property key or null if not resolved
String getProperty(String key, String defaultValue) – Gets the value for a given property key or the given defaultValue if not found
String getRequiredProperty(String key) – Gets the value for a given property key or throws an IllegalStateException if not found
Profiles
Spring Profiles allow you to configure different properties and even Beans to be initialized at runtime depending on the active Profile(s). They can be useful when deploying the same application to different environments, such as “Staging,” “Test,” and “Production.” You can have any number of profiles with any names.
You can set the current Profile or Profiles active using the spring.profiles.active system property or spring_profiles_active environment variable. You can have as many profiles active as you want (separate them using commas).
The @Profile annotation can annotate a @Component bean class (or the stereotype annotations, @Service, @Repository, and @Controller) or a @Bean annotated method or even a @Configuration annotated configuration class.
ProfileDatabaseConfig.java
Make sure you use a different name for each @Bean method in a Configuration class even when those beans are marked for different profiles. Otherwise, you could get unexpected behavior from Spring since it uses the method names for the bean names.
SpEL
What is Spring Expression Language (SpEL)? The Spring Expression Language (SpEL for short) is a powerful expression language that supports querying and manipulating an object graph at runtime.
The T syntax is used to refer to a Java type (the preceding java.lang.Math class).
This would default to 25 if no value was given for pop3.port.
It would result in hello having the value "Hello World!".
SpEL is also useful for Spring Security annotations which we will cover in a subsequent chapter.
Testing
MyTest.java
MyTest5.java
Write a Spring application including a JUnit test.