🫘 Spring Bean

GunhoΒ·2024λ…„ 11μ›” 11일
1

Object Oriented Programming (OOP) & Java

λͺ©λ‘ 보기
17/29

🫘 Spring Bean

🫘 Spring Bean is an object where its lifecycle is managed by the Spring 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

    • followed by @Component Annotation
  • β˜•οΈ @Configuration & @Bean Annotations

    • where @Configuration is @Component in depth
  • πŸ—„οΈ XML

    • the legacy approach with an XML file

🚨 Component Scan

🚨 Component Scan specifically refers to the method where the Spring framework automatically scans any classes or interface (including annotation interface), enum, or record, 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 & @Bean Annotations

β˜•οΈ @Configuration combined with @Bean is strictly an alternative to the conventional Bean registration approach with XML.

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

πŸ—„οΈ XML is a legacy styled approach, where all the bean specification is provided within an XML 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");

πŸ«› Spring Bean Proxy

πŸ«› In Spring, bean proxying is an internal mechanism used by the Spring IoC Container to apply the proxy 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

    • for beans implementing one or more interfaces.
    • creates a proxy instance implementing those interfaces.
  • πŸ“– CGLIB (Code Generation Library)

    • default proxy creator for beans with no interfaces.
    • creates a 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.


🧸 Example

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;
        //
    }
}

πŸ“š References

μŠ€ν”„λ§ μž…λ¬Έμ„ μœ„ν•œ μžλ°” 객체 μ§€ν–₯의 원리와 이해
μŠ€ν”„λ§ 핡심 원리 - 기본편 (κΉ€μ˜ν•œ)
F-Lab

profile
Hello

0개의 λŒ“κΈ€