> **bean 從生到死**
>---
1. Spring 對bean進行實例化。
2. Spring將值和bean的引用注入到bean對應的屬性上。
3. 如果bean實現了BeanNameAware接口,Spring將bean 的ID傳遞給setBeanName() 方法。
4. 如果bean 實現了BeanFactoryAware接口,Spring將調用setBeanFactory()方法,將BeanFactory容器實例傳入。
5. 如果bean實現了ApplicationContextAware接口,Spring 將調用setApplicationContext()方法,將bean所在的應用上下文的引用傳入進來。
6. 如果bean實現了BeanPostProcessor接口,Spring將調用他們的postProcessBeforeInitialization方法。
7. 如果bean 實現了InitializingBean 接口,Spring將調用他們的afterPropertiesSet()類似的,如果bean 使用init-method聲明了初始化方法,該方法也會被調用。
8. 如果bean 實現了BeanPostProcessor接口,Spring將調用他們的postProcessAfterInitialization()方法
9. 此時,bean已經就緒,可以被應用程序使用了,他們將一直駐留在應用程序上下文中,直到該應用上下文被銷毀。
10. 如果bean實現了DisposableBean 接口,Spring將調用destory()接口方法,同樣,如果bean使用destory-method聲明了銷毀方法,該方法也會被調用。
----
>**BeanFactory和FactoryBean**
>---
1. BeanFactory,以Factory結尾,表示它是一個工廠類(接口),用于管理Bean的一個工廠。在Spring中,BeanFactory是IOC容器的核心接口,它的職責包括:實例化、定位、配置應用程序中的對象及建立這些對象間的依賴。Spring為我們提供了許多易用的BeanFactory實現,XmlBeanFactory就是常用的一個,該實現將以XML方式描述組成應用的對象及對象間的依賴關系。XmlBeanFactory類將持有此XML配置元數據,并用它來構建一個完全可配置的系統或應用。
~~~
Resource resource = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
BeanFactory factory = (BeanFactory) context;
~~~
2. 以Bean結尾,表示它是一個Bean,不同于普通Bean的是:它是實現了FactoryBean<T >接口的Bean,根據該Bean的ID從BeanFactory中獲取的實際上是FactoryBean的getObject()返回的對象,而不是FactoryBean本身,如果要獲取FactoryBean對象,請在id前面加一個&符號來獲取。例如自己實現一個FactoryBean,功能:用來代理一個對象,對該對象的所有方法做一個攔截,在調用前后都輸出一行LOG,模仿ProxyFactoryBean的功能。
~~~
/**
* my factory bean<p>
* 代理一個類,攔截該類的所有方法,在方法的調用前后進行日志的輸出
* @author daniel.zhao
*
*/
public class MyFactoryBean implements FactoryBean<Object>, InitializingBean, DisposableBean {
private static final Logger logger = LoggerFactory.getLogger(MyFactoryBean.class);
private String interfaceName;
private Object target;
private Object proxyObj;
@Override
public void destroy() throws Exception {
logger.debug("destroy......");
}
@Override
public void afterPropertiesSet() throws Exception {
proxyObj = Proxy.newProxyInstance(
this.getClass().getClassLoader(),
new Class[] { Class.forName(interfaceName) },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
logger.debug("invoke method......" + method.getName());
logger.debug("invoke method before......" + System.currentTimeMillis());
Object result = method.invoke(target, args);
logger.debug("invoke method after......" + System.currentTimeMillis());
return result;
}
});
logger.debug("afterPropertiesSet......");
}
@Override
public Object getObject() throws Exception {
logger.debug("getObject......");
return proxyObj;
}
@Override
public Class<?> getObjectType() {
return proxyObj == null ? Object.class : proxyObj.getClass();
}
@Override
public boolean isSingleton() {
return true;
}
public String getInterfaceName() {
return interfaceName;
}
public void setInterfaceName(String interfaceName) {
this.interfaceName = interfaceName;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Object getProxyObj() {
return proxyObj;
}
public void setProxyObj(Object proxyObj) {
this.proxyObj = proxyObj;
}
}
~~~
---
~~~
<bean id="fbHelloWorldService" class="com.ebao.xxx.MyFactoryBean">
<propertyname="interfaceName" value="com.ebao.xxx.HelloWorldService" />
<property name="target" ref="helloWorldService" />
</bean>
~~~
---
~~~
@RunWith(JUnit4ClassRunner.class)
@ContextConfiguration(classes = { MyFactoryBeanConfig.class })
public class MyFactoryBeanTest {
@Autowired
private ApplicationContext context;
/**
* 測試驗證FactoryBean原理,代理一個servcie在調用其方法的前后,打印日志亦可作其他處理
* 從ApplicationContext中獲取自定義的FactoryBean
* context.getBean(String beanName) ---> 最終獲取到的Object是FactoryBean.getObejct(),
* 使用Proxy.newInstance生成service的代理類
*/
@Test
public void testFactoryBean() {
HelloWorldService helloWorldService = (HelloWorldService) context.getBean("fbHelloWorldService");
helloWorldService.getBeanName();
helloWorldService.sayHello();
}
}
~~~
---
>**SpringIOC 的理解,其初始化過程?**
> ---
IoC容器是什么?
IoC文英全稱Inversion of Control,即控制反轉,我么可以這么理解IoC容器:
“把某些業務對象的的控制權交給一個平臺或者框架來同一管理,這個同一管理的平臺可以稱為IoC容器。”
我們剛開始學習spring的時候會經常看到的類似下面的這代碼:
~~~
ApplicationContext appContext = new ClassPathXmlApplicationContext("cjj/models/beans.xml");
Person p = (Person)appContext.getBean("person");
~~~
上面代碼中,在創建ApplicationContext實例對象過程中會創建一個spring容器,該容器會讀取配置文件"cjj/models/beans.xml",并統一管理由該文件中定義好的所有bean實例對象,如果要獲取某個bean實例,使用getBean方法就行了。例如我們只需要將Person提前配置在beans.xml文件中(可以理解為注入),之后我們可以不需使用new Person()的方式創建實例,而是通過容器來獲取Person實例,這就相當于將Person的控制權交由spring容器了,差不多這就是控制反轉的概念。
那在創建IoC容器時經歷了哪些呢?為此,先來了解下Spring中IoC容器分類,繼而根據一個具體的容器來講解IoC容器初始化的過程。
Spring中有兩個主要的容器系列:
1. 實現BeanFactory接口的簡單容器;
2. 實現ApplicationContext接口的高級容器。
ApplicationContext比較復雜,它不但繼承了BeanFactory的大部分屬性,還繼承其它可擴展接口,擴展的了許多高級的屬性,其接口定義如下:
~~~
public interface ApplicationContext extends EnvironmentCapable,
ListableBeanFactory, //繼承于BeanFactory
HierarchicalBeanFactory,//繼承于BeanFactory
MessageSource, //
ApplicationEventPublisher,//
ResourcePatternResolver //繼承ResourceLoader,用于獲取resource對象
~~~
在BeanFactory子類中有一個DefaultListableBeanFactory類,它包含了基本Spirng IoC容器所具有的重要功能,開發時不論是使用BeanFactory系列還是ApplicationContext系列來創建容器基本都會使用到DefaultListableBeanFactory類,可以這么說,在spring中實際上把它當成默認的IoC容器來使用。下文在源碼實例分析時你將會看到這個類。
關于Spirng IoC容器的初始化過程在《Spirng技術內幕:深入解析Spring架構與設計原理》一書中有明確的指出,IoC容器的初始化過程可以分為三步:
* Resource定位(Bean的定義文件定位)--定位并獲取資源文件
* 將Resource定位好的資源載入到BeanDefinition --解析資源文件
* 將BeanDefiniton注冊到容器中 --注冊
---
>**BeanFactory和 ApplicationContext?**
>---
在Srping Ioc容器中,有BeanFactory和ApplicationContext兩個系列,分別是:
* 實現BeanFactory接口的簡單容器,具備最基本功能。
* 實現ApplicationContext接口的復雜容器,具備高級功能。
***
1. BeanFactroy采用的是延遲加載形式來注入Bean的,即只有在使用到某個Bean時(調用getBean()),才對該Bean進行加載實例化,這樣,我們就不能發現一些存在的Spring的配置問題。而ApplicationContext則相反,它是在容器啟動時,一次性創建了所有的Bean。這樣,在容器啟動時,我們就可以發現Spring中存在的配置錯誤。 相對于基本的BeanFactory,ApplicationContext 唯一的不足是占用內存空間。當應用程序配置Bean較多時,程序啟動較慢。BeanFacotry延遲加載,如果Bean的某一個屬性沒有注入,BeanFacotry加載后,直至第一次使用調用getBean方法才會拋出異常;而ApplicationContext則在初始化自身是檢驗,這樣有利于檢查所依賴屬性是否注入;所以通常情況下我們選擇使用 ApplicationContext。應用上下文則會在上下文啟動后預載入所有的單實例Bean。通過預載入單實例bean ,確保當你需要的時候,你就不用等待,因為它們已經創建好了。
2. BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但兩者之間的區別是:BeanFactory需要手動注冊,而ApplicationContext則是自動注冊。(Applicationcontext比 beanFactory 加入了一些更好使用的功能。而且 beanFactory 的許多功能需要通過編程實現而 Applicationcontext 可以通過配置實現。比如后處理 bean , Applicationcontext 直接配置在配置文件即可而 beanFactory 這要在代碼中顯示的寫出來才可以被容器識別。 )
3. beanFactory主要是面對與 spring 框架的基礎設施,面對 spring 自己。而 Applicationcontex 主要面對與 spring 使用的開發者。基本都會使用 Applicationcontex 并非 beanFactory 。
---
>**Spring AOP 的實現**
>---
先了解AOP的相關術語:
1. 通知(Advice):
通知定義了切面是什么以及何時使用。描述了切面要完成的工作和何時需要執行這個工作。
2. 連接點(Joinpoint):
程序能夠應用通知的一個“時機”,這些“時機”就是連接點,例如方法被調用時、異常被拋出時等等。
3. 切入點(Pointcut)
通知定義了切面要發生的“故事”和時間,那么切入點就定義了“故事”發生的地點,例如某個類或方法的名稱,Spring中允許我們方便的用正則表達式來指定
4. 切面(Aspect)
通知和切入點共同組成了切面:時間、地點和要發生的“故事”
5. 引入(Introduction)
引入允許我們向現有的類添加新的方法和屬性(Spring提供了一個方法注入的功能)
6. 目標(Target)
即被通知的對象,如果沒有AOP,那么它的邏輯將要交叉別的事務邏輯,有了AOP之后它可以只關注自己要做的事(AOP讓他做愛做的事)
7. 代理(proxy)
應用通知的對象,詳細內容參見設計模式里面的代理模式
8. 織入(Weaving)
把切面應用到目標對象來創建新的代理對象的過程,織入一般發生在如下幾個時機:
* 編譯時:當一個類文件被編譯時進行織入,這需要特殊的編譯器才可以做的到,例如AspectJ的織入編譯器
* 類加載時:使用特殊的ClassLoader在目標類被加載到程序之前增強類的字節代碼
* 運行時:切面在運行的某個時刻被織入,SpringAOP就是以這種方式織入切面的,原理應該是使用了JDK的動態代理技術
Spring提供了4種實現AOP的方式:
1. 經典的基于代理的AOP
2. @AspectJ注解驅動的切面
3. 純POJO切面
4. 注入式AspectJ切面
---
>
>---
- 序
- 求職路
- 筆試準備
- Huawei題庫
- 劍指Offer
- 面試準備
- Java技術棧
- 設計模式
- Java框架
- Spring
- SpringBoot
- SpringCloud
- SpringMVC
- Spring基礎
- ORM
- Hibernate
- MyBatis
- 分布式
- 分布式計算
- 分布式存儲
- 消息隊列
- 消息中間件
- 生產者消費者
- Provider
- Data
- Consumer
- Main
- 校招宣講招聘會
- 哈工大九月
- 數據庫
- MySQL
- Redis
- 面試經歷
- Alibaba
- 第二面-Alibaba
- 第一面-Alibaba
- Xiaomi
- Xiaomi一面
- Xiaomi二面
- Yonyou
- Yonyou一面+HR
- Huawei
- Huawei一面
- Huawei二面
- 一個小結
- 工作路
- 萬里長征第一步
- Huawei簽約
- 技術路
- 開源之路
- 初試探
- 技術棧
- 編程語言
- OpenCV
- 從Java 和C++玩轉OpenCV
- 第一章
- 介紹
- 第一節