BeanFactory
接口的简单容器系列:实现容器的最基本功能ApplicationContext
:增加了许多面向框架的特性,同时对应用环境作了许多适配接口方法:
- containsBean
- isSingleton
- isPrototype
- isTypeMatch
- getType
- getAliases
设计原理:(以XmlBeanFactory
为例)
编程式使用IoC容器:
ClassPathResource res = new ClassPathResource("bean.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
步骤:
1. 创建IoC配置文件的抽象资源,这个抽象资源包含了BeanDefinition
的定义信息
2. 创建一个BeanFactory
,这里使用DefaultListableBeanFactory
3. 创建一个载入BeanDefinition
的读取器,通过一个回调配置给BeanFactory
4. 从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader
来完成。
BeanDefinition的载入和解析:
对IoC容器来说,这个载入过程,相当于把定义的BeanDefinition
在IoC容器中转化为一个Spring内部表示的数据结构的过程,这些BeanDefinition
数据在IoC容器中通过一个HashMap
来保持和维护。
BeanDefinition在IoC容器中的注册:
在DefaultListableBeanFactory
中实现了BeanDefinitionRegistry
的接口,这个接口的实现完成BeanDefinition
向容器的注册,就是把解析得到的BeanDefinition
设置到hashMap
中去。
什么时候注入:在用户第一次向IoC容器索要bean的时候(lazy-init
预实例化除外)
两种实例化Java对象的方法:
- 通过BeanUtils
,使用Java反射功能
- 通过CGLIB
的Enhancer
类的create
方法
Bean的生命周期:
1. Bean实例的创建
2. 为Bean实例设置属性
3. 调用Bean的初始化方法
4. 应用可以通过IoC容器使用Bean
5. 当容器关闭时,调用Bean的销毁方法
lazy-init属性和预实例化:在refresh
初始化容器的时候去getBean
去触发依赖注入
FactoryBean的实现:类似于抽象工厂模式,封装Proxy、RMI、JNDI等
BeanPostProcessor的实现:
两个方法:postProcessBeforeInitialization
/postProcessAfterInitialization
IoC容器对Bean的初始化
- 为类型是BeanNameAware
的Bean设置Bean的名字
- 为类型是BeanClassLoaderAware
的Bean设置类装载器
- 为类型是BeanFactoryAware
的Bean设置自身所在的IoC容器以供回调使用
- 对postProcessBeforeInitialization
/postProcessAfterInitialization
的回调
- 初始化属性init-method
的处理
autowiring(自动依赖装配)的实现
//开始进行依赖注入过程,先处理autowiring的注入
if (mbd.getResolvedAutowiredMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowiredMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
//这里是对autowire注入的处理,根据Bean的名字或者type进行autowire的过程
if (mbd.getResolvedAutowiredMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (mbd.getResolvedAutowiredMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
Advice
通知:
- BeforeAdvice
:接口MethodBeforeAdvice
,方法before()
- AfterAdvice
:接口AfterReturningAdvice
,方法afterReturning()
- ThrowsAdvice
:在抛出异常时回调,这个回调是AOP通过反射机制完成的。
Pointcut
切点:
概念:决定Advice
通知应该作用于哪个连接点。返回一个MethodMatcher
,由它来判断是否需要对当前方法调用进行增强,或者是否需要对当前调用方法应用配置好的Advice
通知。
Advisor通知器:
概念:将Advice
和pointcut
结合起来,可以定义应该使用哪个通知在哪个关注点使用。
ProxyFactoryBean:封装了主要代理对象的生成过程,生成方式有两种
- JDK的Proxy
- CGLIB
JDK生成AopProxy
代理对象
public Obejct getObject(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class[] proxiedInterfaces AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//这是调用JDK生成Proxy的地方
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
JdkDynamicAopProxy
的invoke
拦截:
当Proxy对象的代理方法被调用的时候,JdkDynamicAopProxy
的invoke
方法作为Proxy对象的回调函数被触发,从而通过invoke的具体实现,构造ReflectiveMethodInvocation
对象来完成对目标对象方法调用的拦截或者说功能增强。
Cglib2AopProxy
的intercept
拦截:
与JdkDynamicAopProxy
的回调实现非常类似,唯一不同的是构造CglibMethodInvocation
对象来完成拦截器链的调用。
对目标方法的调用:
- jdk:使用反射机制得到调用方法的反射对象,然后使用invoke启动对方法反射对象的调用。
- cglib:通过MethodProxy
对象来直接invoke完成的
AOP拦截器链的调用:
1. 先进行判断,如果已经运行到拦截器链的末尾,直接调用目标对象的实现方法
2. 否则,沿着拦截器链继续进行,得到下一个拦截器,通过这个拦截器进行matches
判断,是否适用于横切增强的场合,如果是,从拦截器中得到通知器,并启动通知器的invoke
方法进行切面增强
3. 结束之后,迭代调用proceed
方法,直到拦截器链中的拦截器都完成以上的拦截过程为止
配置通知器:
MethodBeforeAdviceAdapter
的实现
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
MethodBeforeAdviceInterceptor
的实现
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
private MethodBeforeAdvice advice;
//为指定的Advice创建对应的MethodBeforeAdviceInterceptor对象
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
//这个invoke方法是拦截器的回调方法,会在代理对象的方法被调用时触发回调
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
}
AfterReturningAdviceInterceptor
的实现
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
/**
* Create a new AfterReturningAdviceInterceptor for the given advice.
* @param advice the AfterReturningAdvice to wrap
*/
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
HotSwappableTaregetSource
:使用户可以以线程安全的方式切换目标对象,提供所谓的热交换功能。
public synchronized Object swap(Object newTarget) throws IllegalArgumentException {
Assert.notNull(newTarget, "Target object must not be null");
Object old = this.target;
this.target = newTarget;
return old;
}
public synchronized Object getTarget() {
return this.target;
}
Web环境中的Spring MVC:
SpringMVC是建立在IoC容器基础上的,该容器由web.xml
里配置的ContextLoaderListener
负责启动的。
Handler
的如何获得:
1. 首先会在HttpRequest
中取得handler
2. 如果没有,则遍历当前DispatcherServlet
持有的所有handlerMapping
,返回需要的handler
。
DispathcherServlet
的render
:
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
// We need to resolve the view name.
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
}
基本配置Bean:
LocalSessionFactoryBean
,生成SessionFactory
,并对Hibernate中的Session
进行管理
Session的管理:
Spring对Hibernate Session
的管理功能都是由SessionFactoryUtils
这个类来提供的。
1. 如果当前线程已绑定事务,Session
使用的Connection
是当前线程绑定的那个
2. 新建Session
和单独使用SessionFactory
打开新Session
一样,都是使用SessionFactory
的openSession
来创建新的Session
iBatis操作数据库的主要类:
SqlMapClient
,类似于Hibernate的Session
,是由SqlMapClientFactoryBean
在依赖注入完成以后被IoC容器回调afterPropertiesSet
中完成创建的。
事务创建的结果是生成一个TransactionStatus
对象,通过这个对象来保存事务处理需要的基本信息,这个是TransactionInfo
的一个属性,然后会把TransactionInfo
保存在ThreadLocal
对象里,这样当前线程可以通过ThreadLocal
对象取得TransactionInfo
以及与这个事务对应的TransactionStatus
对象,从而把处理信息和调用事务方法的当前线程绑定起来。
DataSourceTransactionManager
的实现:
HibernateTransactionManager
的实现:
HTTP调用器客户端完成远端调用的基本过程:
首先由客户端应用调用代理方法,在调用发生以后,代理类会先运行拦截器,对代理的方法调用进行拦截。在拦截器的拦截行为中,先对本地发生的方法调用进行封装 ,具体来说,就是封装成MethodInvocation
对象。然后,把这个MethodInvocation
对象,通过序列化和HTTP请求发送到服务器端,在服务器端的处理完成以后,会通过HTTP响应返回处理结果,这个处理结果被风中在RemoteInvocationResult
对象中。
过程:
1. 从AuthenticationProcessingFilter
拦截HTTP请求开始,接着会从HTTP请求中得到用户输入的用户名和密码,并将这些输入的用户信息放到Authentication
对象中。
2. 将这个Authentication
对象传递给AuthenticationManager
使用,验证器通过持有的Authentication
对象把它和服务端取得的用户信息进行对比,从而完成用户验证。
3. 验证完成以后,ACEGI会把通过验证的、有效的用户信息封装在一个Authentication
对象中,供以后的授权器使用
在验证的实现过程中,需要根据ACEGI的要求,配置好各种Provider、UserDetailService以及密码Encoder对象,通过这些对象的协作和功能实现,完成服务器用户数据的获取与用户输入信息的对比和最终的用户验证工作。
过程:
1. 从FilterSecurityInterceptor
拦截HTTP入手,接着在读取在IoC容器中配置的对URL资源的安全需求以后,会把这些配置信息交由AccessDecisionManager
授权器进行授权决策
2. 配置好授权器以后,还需要配置一些投票器来完成投票工作,支持授权的决策过程,具体对资源的安全请求进行一个判断
3. 授权器根据授权规则对投票器提交的投票结果进行汇总判断,得到最后的决策结果,从而完成最终的授权工作,最终决定该用户对HTTP请求所要求的URL资源是否有权限获取