When Is Maumelle's Spring Clean Up 2019
Providing an Inversion-of-Control Container is one of the core provisions of the Spring Framework. Leap orchestrates the beans in its application context and manages their lifecycle. In this tutorial, we're looking at the lifecycle of those beans and how nosotros tin hook into information technology.
Example Lawmaking
This article is accompanied by a working code example on GitHub.
What Is a Leap Bean?
Let's start with the basics. Every object that is nether the control of Spring's ApplicationContext
in terms of creation, orchestration, and destruction is called a Spring Bean.
The most common manner to define a Bound bean is using the @Component
annotation:
@Component course MySpringBean { ... }
If Spring's component scanning is enabled, an object of MySpringBean
will be added to the awarding context.
Another way is using Leap'due south Java config:
@Configuration class MySpringConfiguration { @Bean public MySpringBean mySpringBean () { return new MySpringBean(); } }
The Spring Bean Lifecycle
When we look into the lifecycle of Spring beans, nosotros can see numerous phases starting from the object instantiation upward to their destruction.
To keep it simple, we group them into creation and destruction phases:
Let's explain these phases in a footling bit more than detail.
Bean Creation Phases
- Instantiation: This is where everything starts for a bean. Spring instantiates bean objects just similar nosotros would manually create a Java object example.
- Populating Properties: After instantiating objects, Jump scans the beans that implement
Enlightened
interfaces and starts setting relevant properties. - Pre-Initialization: Spring'due south
BeanPostProcessor
s go into action in this phase. ThepostProcessBeforeInitialization()
methods do their task. Likewise,@PostConstruct
annotated methods run correct after them. - AfterPropertiesSet: Spring executes the
afterPropertiesSet()
methods of the beans which implementInitializingBean
. - Custom Initialization: Leap triggers the initialization methods that we divers in the
initMethod
attribute of our@Bean
annotations. - Post-Initialization: Bound'due south
BeanPostProcessor
s are in action for the 2d fourth dimension. This phase triggers thepostProcessAfterInitialization()
methods.
Bean Destruction Phases
- Pre-Destroy: Spring triggers
@PreDestroy
annotated methods in this phase. - Destroy: Spring executes the
destroy()
methods ofDisposableBean
implementations. - Custom Devastation: We can define custom devastation hooks with the
destroyMethod
attribute in the@Edible bean
annotation and Spring runs them in the last stage.
Hooking Into the Bean Lifecycle
There are numerous ways to claw into the phases of the edible bean lifecycle in a Spring application.
Allow's come across some examples for each of them.
Using Leap's Interfaces
We tin implement Leap's InitializingBean
interface to run custom operations in afterPropertiesSet()
phase:
@Component class MySpringBean implements InitializingBean { @Override public void afterPropertiesSet () { //... } }
Similarly, we tin implement DisposableBean
to have Bound call the destroy()
method in the destroy phase:
@Component class MySpringBean implements DisposableBean { @Override public void destroy () { //... } }
Using JSR-250 Annotations
Spring supports the @PostConstruct
and @PreDestroy
annotations of the JSR-250 specification.
Therefore, we can use them to hook into the pre-initialization and destroy phases:
@Component course MySpringBean { @PostConstruct public void postConstruct () { //... } @PreDestroy public void preDestroy () { //... } }
Using Attributes of the @Edible bean
Notation
Additionally, when we define our Spring beans we tin can set the initMethod
and destroyMethod
attributes of the @Edible bean
annotation in Coffee configuration:
@Configuration form MySpringConfiguration { @Bean (initMethod = "onInitialize" , destroyMethod = "onDestroy" ) public MySpringBean mySpringBean () { return new MySpringBean(); } }
Nosotros should note that if we have a public method named close()
or shutdown()
in our bean, so it is automatically triggered with a destruction callback by default:
@Component class MySpringBean { public void close () { //... } }
Even so, if we do not wish this behavior, we can disable it by setting destroyMethod=""
:
@Configuration class MySpringConfiguration { @Bean (destroyMethod = "" ) public MySpringBean mySpringBean () { return new MySpringBean(); } }
XML Configuration
For legacy applications, we might have still some beans left in XML configuration. Luckily, we can nevertheless configure these attributes in our XML bean definitions.
Using BeanPostProcessor
Alternatively, we can brand apply of the BeanPostProcessor
interface to be able to run whatsoever custom operation before or later a Spring edible bean initializes and even return a modified bean:
class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { //... render edible bean; } @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { //... return bean; } }
BeanPostProcessor
Is Not Bean Specific
We should pay attention that Spring'due south BeanPostProcessor
s are executed for each bean defined in the spring context.
Using Enlightened
Interfaces
Some other way of getting into the lifecycle is past using the Aware
interfaces:
@Component class MySpringBean implements BeanNameAware, ApplicationContextAware { @Override public void setBeanName (String proper name) { //... } @Override public void setApplicationContext (ApplicationContext applicationContext) throws BeansException { //... } }
At that place are boosted Enlightened
interfaces which we can utilize to inject sure aspects of the Spring context into our beans.
Why Would I Need to Hook Into the Edible bean Lifecycle?
When we need to extend our software with new requirements, information technology is critical to find the best practices to keep our codebase maintainable in the long run.
In Bound Framework, hooking into the edible bean lifecycle is a good way to extend our application in most cases.
Acquiring Edible bean Properties
One of the utilise cases is acquiring the edible bean properties (like bean name) at runtime. For example, when we practice some logging:
@Component class NamedSpringBean implements BeanNameAware { Logger logger = LoggerFactory. getLogger (NamedSpringBean. course ); public void setBeanName (Cord name) { logger. info (name + " created." ); } }
Dynamically Irresolute Spring Bean Instances
In some cases, nosotros need to define Spring beans programmatically. This tin can be a applied solution when we demand to re-create and change our bean instances at runtime.
Permit'southward create an IpToLocationService
service which is capable of dynamically updating IpDatabaseRepository
to the latest version on-need:
@Service form IpToLocationService implements BeanFactoryAware { DefaultListableBeanFactory listableBeanFactory; IpDatabaseRepository ipDatabaseRepository; @Override public void setBeanFactory (BeanFactory beanFactory) throws BeansException { listableBeanFactory = (DefaultListableBeanFactory) beanFactory; updateIpDatabase(); } public void updateIpDatabase (){ String updateUrl = "https://download.tiptop.com/ip-database-latest.mdb" ; AbstractBeanDefinition definition = BeanDefinitionBuilder . genericBeanDefinition (IpDatabaseRepository. course ) . addPropertyValue ( "file" , updateUrl) . getBeanDefinition (); listableBeanFactory . registerBeanDefinition ( "ipDatabaseRepository" , definition); ipDatabaseRepository = listableBeanFactory . getBean (IpDatabaseRepository. class ); } }
We access the BeanFactory
instance with the help of BeanFactoryAware
interface. Thus, we dynamically create our IpDatabaseRepository
bean with the latest database file and update our bean definition past registering it to the Spring context.
Also, we telephone call our updateIpDatabase()
method right after nosotros acquire the BeanFactory
instance in the setBeanFactory()
method. Therefore, nosotros can initially create the first example of the IpDatabaseRepository
bean while the Spring context boots up.
Accessing Beans From the Outside of the Jump Context
Another scenario is accessing the ApplicationContext
or BeanFactory
example from outside of the Spring context.
For example, we may want to inject the BeanFactory
into a not-Spring grade to be able to access Spring beans or configurations inside that grade. The integration between Spring and the Quartz library is a expert example to show this use case:
course AutowireCapableJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { individual AutowireCapableBeanFactory beanFactory; @Override public void setApplicationContext ( last ApplicationContext context) { beanFactory = context. getAutowireCapableBeanFactory (); } @Override protected Object createJobInstance ( final TriggerFiredBundle package) throws Exception { final Object job = super . createJobInstance (bundle); beanFactory. autowireBean (job); return job; } }
In this example, we're using the ApplicationContextAware
interface to get access to the edible bean factory and use the bean manufacturing plant to autowire the dependencies in a Job
bean that is initially not managed by Spring.
Also, a common Jump - Jersey integration is some other clear example of this:
@Configuration class JerseyConfig extends ResourceConfig { @Autowired individual ApplicationContext applicationContext; @PostConstruct public void registerResources () { applicationContext. getBeansWithAnnotation (Path. class ). values () . forEach ( this ::annals); } }
By marking Jersey's ResourceConfig
as a Spring @Configuration
, we inject the ApplicationContext
and lookup all the beans which are annotated past Bailiwick of jersey's @Path
, to hands register them on application startup.
The Execution Social club
Let'southward write a Spring bean to encounter the execution lodge of each phase of the lifecycle:
class MySpringBean implements BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean { individual String message; public void sendMessage (String message) { this . message = message; } public String getMessage () { render this . message ; } @Override public void setBeanName (Cord name) { System. out . println ( "--- setBeanName executed ---" ); } @Override public void setApplicationContext (ApplicationContext applicationContext) throws BeansException { System. out . println ( "--- setApplicationContext executed ---" ); } @PostConstruct public void postConstruct () { Arrangement. out . println ( "--- @PostConstruct executed ---" ); } @Override public void afterPropertiesSet () { System. out . println ( "--- afterPropertiesSet executed ---" ); } public void initMethod () { System. out . println ( "--- init-method executed ---" ); } @PreDestroy public void preDestroy () { System. out . println ( "--- @PreDestroy executed ---" ); } @Override public void destroy () throws Exception { System. out . println ( "--- destroy executed ---" ); } public void destroyMethod () { System. out . println ( "--- destroy-method executed ---" ); } }
Additionally, we create a BeanPostProcessor
to hook into the before and after initialization phases:
class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization (Object edible bean, String beanName) throws BeansException { if (bean instanceof MySpringBean) { System. out . println ( "--- postProcessBeforeInitialization executed ---" ); } return edible bean; } @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { if (bean instanceof MySpringBean) { System. out . println ( "--- postProcessAfterInitialization executed ---" ); } return bean; } }
Adjacent, nosotros write a Bound configuration to define our beans:
@Configuration form MySpringConfiguration { @Bean public MyBeanPostProcessor myBeanPostProcessor (){ return new MyBeanPostProcessor(); } @Bean (initMethod = "initMethod" , destroyMethod = "destroyMethod" ) public MySpringBean mySpringBean (){ return new MySpringBean(); } }
Finally, nosotros write a @SpringBootTest
to run our Leap context:
@SpringBootTest class BeanLifecycleApplicationTests { @Autowired public MySpringBean mySpringBean; @Test public void testMySpringBeanLifecycle () { Cord message = "Howdy World" ; mySpringBean. sendMessage (bulletin); assertThat(mySpringBean. getMessage ()). isEqualTo (message); } }
As a result, our test method logs the execution order between the lifecycle phases:
--- setBeanName executed --- --- setApplicationContext executed --- --- postProcessBeforeInitialization executed --- --- @PostConstruct executed --- --- afterPropertiesSet executed --- --- init-method executed --- --- postProcessAfterInitialization executed --- ... --- @PreDestroy executed --- --- destroy executed --- --- destroy-method executed ---
Conclusion
In this tutorial, we learned what the bean lifecycle phases are, why, and how we hook into lifecycle phases in Jump.
Spring has numerous phases in a bean lifecycle as well equally many ways to receive callbacks. We can claw into these phases both via annotations on our beans or from a mutual grade as we practise in BeanPostProcessor
.
Although each method has its purpose, we should annotation that using Leap interfaces couples our lawmaking to the Bound Framework.
On the other mitt, @PostConstruct
and @PreDestroy
annotations are a part of the Java API. Therefore, we consider them a improve alternative to receiving lifecycle callbacks because they decouple our components even from Jump.
All the code examples and more than are over on Github for yous to play with.
Source: https://reflectoring.io/spring-bean-lifecycle/
Posted by: goldmanvizing.blogspot.com
0 Response to "When Is Maumelle's Spring Clean Up 2019"
Post a Comment