Deployment期间验证

实现一:

     <bean id="theTargetBean" class="..."/>

     <bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean" />
</property>
</bean>

实现二:

     <bean id="theTargetBean" class="..." />

     <bean id="client" class="...">
<property name="targetName" value="theTargetBean" />
</bean>

方式1跟方式2得到的依赖关系完全一致,不同的是方式1在deployment的时候就会去判断名字为theTargetBean的bean是否有定义,方式2要推迟到client被实例化的时候才去判断名字为theTargetBean的bean是否有定义。

XML简写
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
命名空间p表示可以将<property>变成属性p:[name|name-ref]=”id”的方式出现于<bean>定义中;
命名空间c表示可以将<constructor-arg>变成属性c:[name|name-ref]=”id”的方式出现<bean>定义中;

提前初始化
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.foo.AnotherBean"/>
缺省情况下ApplicationContext在Initialization Process的时候就会创建并配置所有Singleton Bean (没有依赖项的bean),如果lazy-init显示设置为true则表示取消提前初始化的功能,从而加快初始化速度并减少内存占用;对于<beans/>使用default-lazy-init=”true”属性进行批量设置。

方法注入(Lookup Method Injection)

Java代码

 public abstract class CommandManager {
protected abstract Command createCommand();
}

Xml代码

 <bean id="command" class="fiona.apple.AsyncCommand" scope="prototype">
<!-- inject dependencies here as required -->
</bean> <bean id="commandManager" class="fiona.apple.CommandManager">
<lookup-method name="createCommand" bean="command"/>
</bean>

CommandManager中的createCommand方法根据不同要求需要不同的实现,通过配置文件的<lookup-method>可以指定不同bean定义的方法实现;如果一个bean是stateful的则需要将scope设置为prototype,在每次调用的时候都生成一个新的instance。
<lookup-method/>标签用于解决当一个singleton的Bean A需要引用另外一个非singleton的Bean B(也就是每一次引用Bean B都需要引用最新创建的实例);实现方式是动态创建一个CommandManager的子类,并复写指定的方法;
AOP综合使用JDK Dynamic Proxy和CGLIB对目标类进行代理,两者区别如下:
#1 JDK Dynamic Proxy方式使用Java Reflection技术,因此要求目标类有一个Interface,并且目标方法需要此Interface中申明,动态创建一个实现了Interface的类并在改类中调用目标类的方法;

 public class PerformanceMonitorProxy implements InvocationHandler {

     private Object target;

     public ServiceWithPerformanceMonitorProxy(Object target) {
this.target = target;
} public static Object newProxyInstance(Object target) {
Class clazz = target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(),
new ServiceWithPerformanceMonitorProxy(target));
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//do something before target function invocation
PerformanceMonitor.begin(method.getName());
Object result = method.invoke(target, args);
//do something after target function invocation
PerformanceMonitor.end(method.getName());
return result;
}
}

#2 CGLIB使用字节码技术,动态生成一个目标类的子类,通过over-write去覆盖目标方法;

 public class CGlibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this); // 代理执行时会回调此this持有的intercept方法,以实现代码织入
return enhancer.create();
} @Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
PerformanceMonitor.begin(method.getName());
Object result = methodProxy.invokeSuper(target, args);
// 下面这样是无法执行原有方法的,因为这里的target并不是原有类的实例,而是代理类的实例
// target :
// com.dianping.aop.AdminServiceImpl$$EnhancerByCGLIB$$225da297@16dd5a9d
// Object result = method.invoke(target, args);
PerformanceMonitor.end(method.getName());
return result;
}
}

Spring一般首选JDK Dynamic Proxy进行代理,如果遇到没有实现Interface的情况则使用CGLIB,当然可以通过下属设置强制使用CGLIB;

 <aop:config proxy-target-class="true">
<!-- other beans defined here... -->
</aop:config>

Bean作用范围 (<bean ………. Scope=”…….” />)

Singleton:缺省值,一个Spring IoC容器中至多仅生成一个instance,被依赖者共享,stateless
Prototype:每次调用都会生成一个新的instance,不同依赖者使用不同的实例,stateful
Request:WebApplicationContext中一次HTTP请求中至多仅生成一个instance
Session:WebApplicationContext中一个HTTP Session中至多仅生成一个instance
Global Session:WebApplicationContext中一个Global HTTP Session中至多仅生成一个instance
Application:WebApplicationContext中一个ServletContext中至多仅生成一个instance

     <bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
<aop:scoped-proxy/>
</bean> <!-- a singleton-scoped bean injected with a proxy to the above bean -->
<bean id="userService" class="com.foo.SimpleUserService">
<property name="userPreferences" ref="userPreferences"/>
</bean>

<aop:scoped-proxy/>用于解决将一个shorter-lived scoped bean注入到一个longer-lived scoped bean时shorter-lived scoped bean提前失效的场景;由于singleton类仅有一次注入bean的机会,因此解决思路是在一开始就在longer-lived scoped bean(singleton)中注入一个proxy class作为代理类,如果shorter-lived scoped bean(session)已经失效,代理类会使用当前session scope的shorter-lived bean。

定制Bean的初始化和销毁动作

方法一:使用标注@PostConstruct和@PreDestroy;在bean的java类文件中添加。
这两个标注由CommonAnnotationBeanPostProcessor进行处理。

 @PostConstruct
public void init(){
System.out.println("init method”);
}
@PreDestroy
public void dostory(){
System.out.println("destory method");
}

方法二:使用xml配置属性init-method和destroy-method,或者在<beans/>中添加批量设置的属性default-init-method或者default-destroy-method;

 <bean id="initAndDestroySeqBean"
class="com.chj.spring.InitAndDestroySeqBean"
init-method="initMethod"
destroy-method="destroyMethod"/>

方法三:使用接口InitializingBean和DisposableBean (不推荐)

 public class PersonService  implements InitializingBean,DisposableBean{
@Override
public void destroy() throws Exception {
// TODO Auto-generated method stub
System.out.println("init method");
}
@Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
System.out.println("init method");
}
}

执行顺序为@PostConstruct -> InitializingBean -> init-method

如果POJO需要获取容器的某些消息,可以实现下述接口;但是一旦实现这些接口之后就与Spring框架强耦合;

 public interface ApplicationContextAware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
public interface BeanNameAware {
void setBeanName(string name) throws BeansException;
}

Bean继承

当需要创建同一个class或者同一个parent class的多个不同状态的instance时,使用parent属性可以有效减少配置文件中需要填写的属性值;

 <bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean> <bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from parent -->
</bean>

#1 inheritsTestBean中的abstract=true表示当前bean不能实例化;如果一个singleton bean不打算进行实例化,则需要加上abstract=true属性。
#2 inheritsWithDifferentClass中的class属性不需要extends自parent class,但必须与parent class bean定义的属性匹配;并且可省略,表示使用parent指定bean的class属性;

Spring容器扩展点接口
BeanPostProcessor可以进行customized的实例化、初始化、依赖装配、依赖验证等流程(处理annotation标签,比如@Autowired,@Resource等)。
BeanFactoryPostProcessor可以修改xml文件的bean metadata;Ordered接口控制先后执行顺序。

自动装配(Autowiring)
XML Injection在Annotation Injection之后执行,所以前者会覆盖后者的相同设置,比如如果<property/>或者<constructor-arg/>也针对同一属性进行装配,则@Autowire装配的内容被覆盖;自动装配不能指定简单类型,如String;并且容易造成匹配歧义从而抛出异常;

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> </beans>

‘<context:annotation-config>’表示使用annotation对属性进行自动装配,同时还注册了一系列post processors(比如AutowiredAnnotationBeanPostProcessor);加入上述tag之后就可以在java class中使用如下annotation了。

@Required:应用于属性的setter方法,表示相关的property必须设置值,否则抛出异常,但不检查是否为空。
@Autowired:应用于属性或者属性的setter方法, 表示相关的property必须有且仅有一个匹配项;如果应用于Spring自定义的Interface(如ApplicationContext)则容器会自动赋值匹配,无需额外进行设置;@Autowired是基于类型匹配的,所以如果一个bean是collection或者map则不能用@Autowired而需要使用@Resource。

深入理解Spring IoC容器和动态代理机制的更多相关文章

  1. 理解 Spring IoC 容器

    控制反转与大家熟知的依赖注入同理, 这是通过依赖注入对象的过程. 创建 Bean 后, 依赖的对象由控制反转容器通过构造参数 工厂方法参数或者属性注入. 创建过程相对于普通创建对象的过程是反向, 称之 ...

  2. 深入理解Spring IOC容器

    本文将从纯xml模式.xml和注解结合.纯注解的方式讲解Spring IOC容器的配置和相关应用. 纯XML模式 实例化Bean的三种方式: 使用无参构造函数 默认情况下,会使用反射调用无参构造函数来 ...

  3. 深入理解Spring IOC容器及扩展

    本文将从纯xml模式.xml和注解结合.纯注解的方式讲解Spring IOC容器的配置和相关应用. 纯XML模式 实例化Bean的三种方式: 使用无参构造函数 默认情况下,会使用反射调用无参构造函数来 ...

  4. Spring AOP中的动态代理

    0  前言 1  动态代理 1.1 JDK动态代理 1.2 CGLIB动态代理 1.2.1 CGLIB的代理用法 1.2.2 CGLIB的过滤功能 2  Spring AOP中的动态代理机制 2.1  ...

  5. 转:Spring AOP中的动态代理

    原文链接:Spring AOP中的动态代理 0  前言 1  动态代理 1.1 JDK动态代理 1.2 CGLIB动态代理 1.2.1 CGLIB的代理用法 1.2.2 CGLIB的过滤功能 2  S ...

  6. 【转】Spring学习---Spring IoC容器的核心原理

    [原文] Spring的两个核心概念:IoC和AOP的雏形,Spring的历史变迁和如今的生态帝国. IoC和DI的基本概念 IoC(控制反转,英文含义:Inverse of Control)是Spr ...

  7. Spring IOC 容器源码分析 - 填充属性到 bean 原始对象

    1. 简介 本篇文章,我们来一起了解一下 Spring 是如何将配置文件中的属性值填充到 bean 对象中的.我在前面几篇文章中介绍过 Spring 创建 bean 的流程,即 Spring 先通过反 ...

  8. Spring IOC 容器源码分析

    声明!非原创,本文出处 Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 S ...

  9. Spring IOC容器启动流程源码解析(四)——初始化单实例bean阶段

    目录 1. 引言 2. 初始化bean的入口 3 尝试从当前容器及其父容器的缓存中获取bean 3.1 获取真正的beanName 3.2 尝试从当前容器的缓存中获取bean 3.3 从父容器中查找b ...

随机推荐

  1. (DP)51NOD 1006 最长公共子序列&1092 回文字符串

    1006 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为:   abcicba abdkscab   ab是两个串的子序列,abc也是,abca也是,其中abc ...

  2. 语句-python while,for

    1.while语句-死循环 #死循环,while只有条件为假时才跳出循环 while True: print('一个小苹果') 2.while语句-带有计数格式的循环 #带有计数格式的循环 var = ...

  3. profile和bashrc

    转自某不知名网友 /etc/profile,/etc/bashrc 是系统全局环境变量设定~/.profile,~/.bashrc用户家目录下的私有环境变量设定当登入系统时候获得一个shell进程时, ...

  4. Django models数据库配置以及多数据库调用设置

    今天来说说web框架Django怎么配置使用数据库,也就是传说中MVC(Model View Controller)中的M,Model(模型). 简单介绍一下Django中的MVC: 模型(model ...

  5. Python 基础知识(5)

    1:引用 当我们把一个变量给另一个变量赋值的时候,不是把A变量中的值给B一份,而是把A变量中的地址给了B,这就是引用.任何牵扯到等号赋值的地方,统统都是引用. a = 100 b = a id(a) ...

  6. PWA之push服务

    转载: https://www.jishux.com/p/c5735af96c39bd4a https://www.jianshu.com/p/9970a9340a2d 系列文章参考:https:// ...

  7. Python Selenium设计模式 - PO设计模式

    整理一下python selenium自动化测试实践中使用较多的po设计模式. 为什么要用PO 基于python selenium2开始开始ui自动化测试脚本的编写不是多么艰巨的任务.只需要定位到元素 ...

  8. Ionic之页面传值

    很多时候,我们都进入一个页面往往都是需要将上一级的数据转入到下一级页面中使用,在传传统的html中时经过url来传值,所以ionic也是沿用了html中的方法. 但是还是有点区别于html.我们直接在 ...

  9. AJPFX关于对集合中的元素删除操作和注意点

    import java.util.ArrayList;import java.util.Iterator;import java.util.List; public class ForeTest2 { ...

  10. Git之master ->! [rejected] master (non-fast-forward)

    出现这个情况可能是在克隆项目的时候强制关闭或者是在pull的时候强制关闭 运行命令:git pull --rebase origin master 然后就可以 git push origin mast ...