7.修改BeanDefinition
Spring IOC在實例化Bean對象之前,需要先讀取Bean的相關屬性,保存到BeanDefinition
對象中,然后通過BeanDefinition對象,實例化Bean對象。
如果想修改BeanDefinition對象中的屬性,該怎么辦呢?
答:我們可以實現BeanFactoryPostProcessor
接口。
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
beanDefinitionBuilder.addPropertyValue("id", 123);
beanDefinitionBuilder.addPropertyValue("name", "蘇三說技術");
defaultListableBeanFactory.registerBeanDefinition("user", beanDefinitionBuilder.getBeanDefinition());
}
}
在postProcessBeanFactory方法中,可以獲取BeanDefinition的相關對象,并且修改該對象的屬性。
8.初始化Bean前后
有時,你想在初始化Bean前后,實現一些自己的邏輯。
這時可以實現:BeanPostProcessor
接口。
該接口目前有兩個方法:
- postProcessBeforeInitialization 該在初始化方法之前調用。
- postProcessAfterInitialization 該方法再初始化方法之后調用。
例如:
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof User) {
((User) bean).setUserName("蘇三說技術");
}
return bean;
}
}
如果spring中存在User對象,則將它的userName設置成:蘇三說技術。
其實,我們經常使用的注解,比如:@Autowired、@Value、@Resource、@PostConstruct等,是通過AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor實現的。
9.初始化方法
目前spring中使用比較多的初始化bean的方法有:
- 使用@PostConstruct注解
- 實現InitializingBean接口
9.1 使用@PostConstruct注解
@Service
public class AService {
@PostConstruct
public void init() {
System.out.println("===初始化===");
}
}
在需要初始化的方法上增加@PostConstruct
注解,這樣就有初始化的能力。
9.2 實現InitializingBean接口
@Service
public class BService implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("===初始化===");
}
}
實現InitializingBean
接口,重寫afterPropertiesSet
方法,該方法中可以完成初始化功能。
10.關閉容器前
有時候,我們需要在關閉spring容器前,做一些額外的工作,比如:關閉資源文件等。
這時可以實現DisposableBean
接口,并且重寫它的destroy
方法:
@Service
public class DService implements InitializingBean, DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean afterPropertiesSet");
}
}
這樣spring容器銷毀前,會調用該destroy方法,做一些額外的工作。
通常情況下,我們會同時實現InitializingBean和DisposableBean接口,重寫初始化方法和銷毀方法。
11.自定義作用域
我們都知道spring默認支持的Scope
只有兩種:
- singleton 單例,每次從spring容器中獲取到的bean都是同一個對象。
- prototype 多例,每次從spring容器中獲取到的bean都是不同的對象。
spring web又對Scope進行了擴展,增加了:
- RequestScope 同一次請求從spring容器中獲取到的bean都是同一個對象。
- SessionScope 同一個會話從spring容器中獲取到的bean都是同一個對象。
即便如此,有些場景還是無法滿足我們的要求。
比如,我們想在同一個線程中從spring容器獲取到的bean都是同一個對象,該怎么辦?
這就需要自定義Scope了。
第一步實現Scope接口:
public class ThreadLocalScope implements Scope {
private static final ThreadLocal THREAD_LOCAL_SCOPE = new ThreadLocal();
@Override
public Object get(String name, ObjectFactory> objectFactory) {
Object value = THREAD_LOCAL_SCOPE.get();
if (value != null) {
return value;
}
Object object = objectFactory.getObject();
THREAD_LOCAL_SCOPE.set(object);
return object;
}
@Override
public Object remove(String name) {
THREAD_LOCAL_SCOPE.remove();
return null;
}
@Override
public void registerDestructionCallback(String name, Runnable callback) {
}
@Override
public Object resolveContextualObject(String key) {
return null;
}
@Override
public String getConversationId() {
return null;
}
}
第二步將新定義的Scope注入到spring容器中:
@Component
public class ThreadLocalBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerScope("threadLocalScope", new ThreadLocalScope());
}
}
第三步使用新定義的Scope:
@Scope("threadLocalScope")
@Service
public class CService {
public void add() {
}
}
-
spring
+關注
關注
0文章
338瀏覽量
14308 -
AOP
+關注
關注
0文章
40瀏覽量
11088 -
IOC
+關注
關注
0文章
28瀏覽量
10089
發布評論請先 登錄
相關推薦
評論