> **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
- 第一章
- 介绍
- 第一节