π« Spring Bean
is anobject
where itslifecycle
is managed by theSpring IoC Container
.
Spring Bean
by its nature, is designed as a Singleton
where there is only a single instance
across the application
, and the Spring IoC Container
automatically handles the Spring Bean
creation and relevant DI
.
Spring Bean
can be initialised by the following approaches:
π¨ Component Scan
@Component Annotation
βοΈ @Configuration & @Bean Annotations
@Configuration
is @Component
in depthποΈ XML
XML
fileπ¨
Component Scan
specifically refers to the method where theSpring framework
automatically scans anyclasses
orinterface
(includingannotation interface
),enum
, orrecord
, declared with@Component annotation
.
@SpringBootApplication
specifically runs the component scan
over the specified path
and its sub-paths
, where by default, it scans the paths
and its subpaths where the application file
is located.
Below could be a good example of a Spring Component
. Spring framework
is responsible for managing the lifecycle
of a ScanMe instance
, and if necessary, BEAN_NAME
could be further specified for better Spring Bean
retrieval.
@Component
@Component(BEAN_NAME)
public class ScanMe {
}
Following that component scan
is applied to annotation interfaces
as well, automatic component scan
also occurs to all annotations
that implicitly include @Component annotation
.
The most frequently used extended annotations
are namely:
@Controller
@Service
@Repository
@Configuration
and as the names suggest, these annotations appear to have more well-understandable implications than they had been declared as @Component
.
βοΈ
@Configuration
combined with@Bean
is strictly an alternative to the conventionalBean
registration approach withXML
.
As mentioned above, @Configuration
in depth functions upon @Component annotation
where @Configuration
is bound to the component scan
.
Bean initialisation
with @Configuration
however, differs to the component scan
as the earlier has to further provide @Bean annoated methods
that instantiates, configures, and initialises a new object
to be managed by the Spring IoC Container
.
Underneath could be a good example of @Configuration
with @Bean annotations
:
AppConfig class
@Configuration
public class AppConfig {
@Bean
public MyServiceImpl myService() {
return new MyServiceImpl();
}
@Bean(BEAN_NAME)
public MyServiceImpl myService() {
return new MyServiceImpl();
}
@Bean
public A a() {
return new A(b);
}
@Bean
public B b() {
return new B();
}
}
BEAN_NAME
specific to the Spring Bean object
can be further specified, and registered Beans
can be used for constructor DI
, where often, following Dependency Inversion Principle
combined with constructor DI
, an instance
of a concrete class
has to be externally injected.
By default, the above configuration
will be instantiated automatically by the Spring framework
. Perhaps for testing purposes, SpringBean Container
can be manually instantiated and its bean
can be retrieved as below:
ApplicationContext
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myServiceImpl = ac.getBean("myServiceImpl", MyServiceImpl.class);
ποΈ
XML
is alegacy styled
approach, where all thebean
specification is provided within anXML
file.
Underneath is a good example:
<?xml version="1.0" encoding="UTF-8"?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
and the above metadata
can be either configured automatically or manually (perhaps for testing) like below, where the file paths
are provided to a constructor
of ClassPathXmlApplicationContext
class
:
ApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
π« In
Spring
,bean proxying
is aninternal mechanism
used by theSpring IoC Container
to apply theproxy pattern
.
Instead of directly managing instances
of the beans
(i.e., the actual class instances
), Spring
injects proxy instances
that represent these beans
.
A Spring Bean Proxy
is implemented via:
πΏ JDK Dynamic Proxy
beans
implementing one or more interfaces
.proxy instance
implementing those interfaces
.π CGLIB
(Code Generation Library
)
proxy creator
for beans
with no interfaces
.subclass proxy
Spring
manipulates the Java
bytecode
to create proxies
, and the proxy mechanism
allows Spring
to intercept bean creation
and execution
by implementing certain additional behaviours such as transaction management
, security checks
, or lazy initialisation
that could be strictly necessary for the Spring applications
.
Spring AOP
and Spring DI
are good examples of Spring Bean Proxies
where extra logics
are further implemented behind the scenes.
Underneath could be a good practical example of bean proxying
, in which given the Spring
@Configuration
, its instance
is registered as a Spring Bean Proxy
followed by $$SpringCGLIB$$0
.
// Configuration
@Configuration
public class AppConfig {
@BEAN
public SPRING_BEAN SPRING_BEAN() {
return new SPRING_BEAN();
}
}
}
// test
@Test
void configurationDeep() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
// bean = class hello.core.AppConfig$$SpringCGLIB$$0
}
Spring
applies a proxy pattern
to intercept the instance creation
and ultimately apply communal logics
critical for Spring framework
.
Assumably, following the Spring IoC Container
's internal mechanism
where it registers bean
and returns a singleton instance
for every Spring Bean calls
, a proxy
of the above config class
could be illustrated as below:
@Configuration
public class AppConfig {
@BEAN
public SPRING_BEAN SPRING_BEAN() {
if (SPRING_BEAN is in Spring IoC Container) {
return SPRING_BEAN in Spring IoC Container;
} else { // NO SPRING_BEAN in Spring IoC Container
// instantiate SPRING_BEAN and register in Spring IoC Container
return SPRING_BEAN
}
}
}
and a proxy
for specific Spring Bean
may be as well altered to an original instance
where the extra logics
wrapping the original method invocation
could be applied:
public class SPRING_BEAN_PROXY extends SPRING_BEAN {
@Override
public void sth() {
// BEFORE
RUN SOMETHING;
//
super.sth(); // SPRING_BEAN.sth();
// AFTER
RUN SOMETHING;
//
}
}
μ€νλ§ μ
λ¬Έμ μν μλ° κ°μ²΄ μ§ν₯μ μ리μ μ΄ν΄
μ€νλ§ ν΅μ¬ μ리 - κΈ°λ³ΈνΈ (κΉμν)
F-Lab