新聞中心
通常情況下,應(yīng)用程序開發(fā)人員不需要對ApplicationContext實(shí)現(xiàn)類進(jìn)行子類化。相反,SpringIoC容器可以通過插入特殊集成接口的實(shí)現(xiàn)來進(jìn)行擴(kuò)展。接下來的幾節(jié)將描述這些集成接口。

創(chuàng)新互聯(lián)公司為企業(yè)級客戶提高一站式互聯(lián)網(wǎng)+設(shè)計(jì)服務(wù),主要包括成都做網(wǎng)站、網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè)、重慶APP開發(fā)公司、小程序設(shè)計(jì)、宣傳片制作、LOGO設(shè)計(jì)等,幫助客戶快速提升營銷能力和企業(yè)形象,創(chuàng)新互聯(lián)各部門都有經(jīng)驗(yàn)豐富的經(jīng)驗(yàn),可以確保每一個作品的質(zhì)量和創(chuàng)作周期,同時每年都有很多新員工加入,為我們帶來大量新的創(chuàng)意。
通過使用BeanPostProcessor來定制Bean
BeanPostProcessor接口定義了回調(diào)方法,你可以實(shí)現(xiàn)這些方法來提供你自己的(或覆蓋容器的默認(rèn))實(shí)例化邏輯、依賴性解析邏輯等等。如果你想在Spring容器完成實(shí)例化、配置和初始化Bean之后實(shí)現(xiàn)一些自定義邏輯,你可以插入一個或多個自定義BeanPostProcessor實(shí)現(xiàn)。
你可以配置多個BeanPostProcessor實(shí)例,你可以通過設(shè)置order屬性控制這些BeanPostProcessor實(shí)例的運(yùn)行順序。只有當(dāng)BeanPostProcessor實(shí)現(xiàn)了Ordered接口時,你才能設(shè)置這個屬性。如果你編寫自己的BeanPostProcessor,你也應(yīng)該考慮實(shí)現(xiàn)Ordered接口。更多細(xì)節(jié),請參見BeanPostProcessor和Ordered接口的javadoc。也請看關(guān)于BeanPostProcessor實(shí)例的程序化注冊的說明。
BeanPostProcessor實(shí)例對Bean實(shí)例進(jìn)行操作。也就是說,SpringIoC容器實(shí)例化一個Bean實(shí)例,然后由BeanPostProcessor實(shí)例進(jìn)行工作。BeanPostProcessor實(shí)例在每個容器中都有作用域。這只有在你使用容器層次結(jié)構(gòu)時才有意義。如果你在一個容器中定義了一個BeanPostProcessor,它只對該容器中的Bean進(jìn)行后處理。換句話說,在一個容器中定義的Bean不會被另一個容器中定義的BeanPostProcessor進(jìn)行后處理,即使這兩個容器是同一層次結(jié)構(gòu)的一部分。
ApplicationContext會自動檢測配置元數(shù)據(jù)中定義了實(shí)現(xiàn)BeanPostProcessor接口的Bean。ApplicationContext將這些 bean 注冊為后處理器,以便以后在創(chuàng)建 bean 時可以調(diào)用它們。Bean后處理器可以像其他Bean一樣被部署在容器中。
請注意,當(dāng)通過在配置類上使用 @Bean 工廠方法來聲明 BeanPostProcessor 時,工廠方法的返回類型應(yīng)該是實(shí)現(xiàn)類本身或至少是org.springframework.beans.factory.config.BeanPostProcessor 接口,明確指出該 Bean的后處理器性質(zhì)。否則,ApplicationContext無法在完全創(chuàng)建它之前按類型自動檢測它。由于BeanPostProcessor需要盡早被實(shí)例化,以便應(yīng)用于上下文中其它Bean的初始化,所以這種早期的類型檢測是至關(guān)重要的。
下面的例子展示了如何在ApplicationContext的上下文中編寫、注冊和使用BeanPostProcessors。
public class HelloWorld {
private String message;
public void setMessage(String message){
this.message = message;
}
public void getMessage(){
System.out.println("Your Message : " + message);
}
public void init(){
System.out.println("Bean is going through init.");
}
public void destroy(){
System.out.println("Bean will destroy now.");
}
}import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;
public class InitHelloWorld implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("BeforeInitialization : " + beanName);
return bean; // you can return any other object as well
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("AfterInitialization : " + beanName);
return bean; // you can return any other object as well
}
}
以下是MainApp.java文件的內(nèi)容。這里你需要注冊一個shutdown鉤子 registerShutdownHook()方法,該方法在AbstractApplicationContext類上聲明。這將確保一個優(yōu)雅的shutdown,并調(diào)用相關(guān)的銷毀方法。
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
context.registerShutdownHook();
}
}
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
init-method = "init" destroy-method = "destroy">
Output:
BeforeInitialization : helloWorld
Bean is going through init.
AfterInitialization : helloWorld
Your Message : Hello World!
Bean will destroy now.
BeanFactoryPostProcessor的實(shí)現(xiàn)被用來讀取配置元數(shù)據(jù),并在IOC容器實(shí)例化Bean之前對其進(jìn)行修改。我們可以配置多個BeanFactoryPostProcessor,你還可以通過設(shè)置order屬性來控制這些BeanFactoryPostProcessor的執(zhí)行順序。只有當(dāng)BeanFactoryPostProcessor實(shí)現(xiàn)了Ordered接口時,你才能設(shè)置order屬性。
BeanFactoryPostProcessor是一個功能接口,它有一個抽象方法postProcessBeanFactory(),實(shí)現(xiàn)這個方法,可以自定義修改Bean定義。請注意,當(dāng)這個方法被調(diào)用時,所有的Bean定義都已經(jīng)被加載,但還沒有Bean被實(shí)例化。它允許重寫或添加屬性,即使是對急于初始化的Bean。BeanFactoryPostProcessor定義如下:
@FunctionalInterface
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException;
}
BeanFactoryPostProcessor示例
舉個簡單的例子,假如我們已經(jīng)在properties配置文件中為數(shù)據(jù)庫配置設(shè)置了屬性,但在運(yùn)行時我們想更改url,其它屬性保持不變,我們可以用BeanFactoryPostProcessor訪問bean定義,并修改屬性值。當(dāng)然,我們可以配置多個properties文件,并進(jìn)行切換,這里僅做一個示例。
- db.properties
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/netjs
db.username=root
db.password=admin
pool.initialSize=5
- datasource定義
- BeanFactoryPostProcessor實(shí)現(xiàn)類
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.Ordered;
public class TestDBPostProcessor implements BeanFactoryPostProcessor, Ordered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
System.out.println("In postProcessBeanFactory");
// Getting the dataSource bean
BeanDefinition bd = beanFactory.getBeanDefinition("dataSource");
if(bd.hasPropertyValues()){
MutablePropertyValues pvs = bd.getPropertyValues();
PropertyValue[] pvArray = pvs.getPropertyValues();
for (PropertyValue pv : pvArray) {
System.out.println("pv -- " + pv.getName());
// changing value for url property
if(pv.getName().equals("url")){
pvs.add(pv.getName(), "jdbc:mysql://localhost:3306/TestSchema");
}
}
}
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 0;
}
}
- 在配置文件中注冊BeanFactoryPostProcessor
public ListfindAllEmployees() {
System.out.println("URL " + ((BasicDataSource)jdbcTemplate.getDataSource()).getUrl());
return this.jdbcTemplate.query(SELECT_ALL_QUERY, (ResultSet rs) -> {
Listlist = new ArrayList ();
while(rs.next()){
Employee emp = new Employee();
emp.setEmpId(rs.getInt("id"));
emp.setEmpName(rs.getString("name"));
emp.setAge(rs.getInt("age"));
list.add(emp);
}
return list;
});
}
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext
("appcontext.xml");
EmployeeDAO dao = (EmployeeDAO)context.getBean("employeeDAOImpl");
List empList = dao.findAllEmployees();
for(Employee emp : empList){
System.out.println("Name - "+ emp.getEmpName() + " Age - "
+ emp.getAge());
}
context.close();
}
} Output:
In postProcessBeanFactory
pv -- driverClassName
pv -- url
pv -- username
pv -- password
pv – initialSize
URL jdbc:mysql://localhost:3306/TestSchema
FactoryBean
在Spring的bean容器中,有兩種bean:普通bean和工廠bean。Spring直接使用前者,而后者可以自己產(chǎn)生對象,由框架來管理。簡單地說,我們可以通過實(shí)現(xiàn)org.springframework.beans.factory.FactoryBean接口來建立一個工廠bean。
FactoryBean接口提供了三種方法:
- T getObject():返回該工廠創(chuàng)建對象的一個實(shí)例。該實(shí)例可能會被共享,這取決于該工廠是返回單體還是原型Bean。
- boolean isSingleton():如果這個FactoryBean返回單體,則返回true,否則返回false。這個方法的默認(rèn)實(shí)現(xiàn)會返回true。
- Class getObjectType():返回由getObject()方法返回的對象類型,如果事先不知道該類型,則返回null。
示例:
public class Tool {
private int id;
// standard constructors, getters and setters
}public class ToolFactory implements FactoryBean{
private int factoryId;
private int toolId;
@Override
public Tool getObject() throws Exception {
return new Tool(toolId);
}
@Override
public Class> getObjectType() {
return Tool.class;
}
@Override
public boolean isSingleton() {
return false;
}
// standard setters and getters
}
@Configuration
public class FactoryBeanAppConfig {
@Bean(name = "tool")
public ToolFactory toolFactory() {
ToolFactory factory = new ToolFactory();
factory.setFactoryId(7070);
factory.setToolId(2);
return factory;
}
}
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(FactoryBeanAppConfig.class);
Tool tool = context.getBean("tool", Tool.class);
System.out.println(tool);
ToolFactory toolFactory = context.getBean("&tool",ToolFactory.class);
System.out.println(toolFactory);
context.close();
}
}當(dāng)我們要獲取FactoryBean實(shí)例時,需要在bean的id前面加上&符號,比如getBean('&tool')。
網(wǎng)頁名稱:Spring框架之Spring容器擴(kuò)展
轉(zhuǎn)載來源:http://fisionsoft.com.cn/article/dpsspdi.html


咨詢
建站咨詢
