控制反转 IoC
Spring 的依赖注入
构造函数注入
public class MyBean {private OtherBean bean;private String name;// 构造函数注入public MyBean(OtherBean otherBean, String name) {this.bean = otherBean;this.name = name;}}
<!-- 其他注入的bean --><bean id="otherBean" class="com.alberto.service.impl.OtherBean" /><!-- 通过构造器注入的bean,id是注入的bean名称,ref是通过名称找到的bean --><bean id="myBean" class="com.alberto.service.impl.MyBean"><!-- 不止index,也可以用name属性,类似于下面setter注入的name,不同之处是name为构造器的参数变量名,类似的还有根据type --><constructor-arg index="0" type="com.alberto.service.impl.OtherBean" ref="otherBean"/><constructor-arg index="1" type="java.lang.String" value="default_string_value"/></bean>
setter 注入
public class MyBean {private OtherBean bean;private String name;// setter注入public void setBean(OtherBean otherBean) {this.bean = otherBean;}// setter注入public void setName(String name) {this.name = name;}}
<!-- 其他注入的bean --><bean id="otherBean" class="com.alberto.service.impl.OtherBean" /><!-- 通过setter注入的bean --><bean id="myBean" class="com.alberto.service.impl.MyBean"><!-- property的name不是字段名,而是setXxx方法中的Xxx --><property name="bean" type="com.alberto.service.impl.OtherBean" ref="otherBean"/><property name="name" type="java.lang.String" value="default_string_value"/></bean>
工厂注入
静态工厂注入
// 使用静态工厂注入一个OtherBean,再将该otherBean通过setter注入到MyBeanpublic class MyStaticFactory {public static OtherBean getOtherBean() {return new OtherBean();}}public class MyBean {private OtherBean bean;private String name;// setter注入public void setBean(OtherBean otherBean) {this.bean = otherBean;}// setter注入public void setName(String name) {this.name = name;}}
<!-- 调用factory的方法获取bean --><bean id="otherBean" class="com.alberto.factory.MyStaticFactory" factory-method="getOtherBean" /><bean id="myBean" class="com.alberto.service.impl.MyBean"><property name="bean" type="com.alberto.service.impl.OtherBean" ref="otherBean"/><property name="name" type="java.lang.String" value="default_string_value"/></bean>
实例工厂注入
// 使用实例工厂注入所需要的全部bean,再将这些bean注入到MyBeanpublic class MyInstanceFactory {public OtherBean getOtherBean() {return new OtherBean();}public String getName() {return "default_string_value";}}public class MyBean {private OtherBean bean;private String name;// setter注入public void setBean(OtherBean otherBean) {this.bean = otherBean;}// setter注入public void setName(String name) {this.name = name;}}
<!-- 调用factory的方法注册两个bean --><bean id="factory" class="com.alberto.factory.MyInstanceFactory" /><bean id="otherBean" factory-bean="factory" factory-method="getOtherBean" /><bean id="name" factory-bean="factory" factory-method="getName" /><!-- 将注册好的bean再注册到myBean中 --><bean id="myBean" class="com.alberto.service.impl.MyBean"><property name="otherBean" ref="otherBean"/><property name="name" ref="name"/></bean>
@Autowired 与 @Resource
@Autowired |
@Resource |
|
|---|---|---|
| 来源 | Spring | J2EE |
| 作用范围 | 字段、setter、构造器 | 字段、setter |
| 默认装配方式 | 按类型 | 按名称 |
| 改变装配方式 | 默认优先顺序:类型 -> 名称; 结合 @Qualifier 按名称装配 |
默认优先顺序:名称 -> 类型 |
| 可选属性 | required:允许 Bean 为 null |
name:指定 Bean 的名称type:指定 Bean 的类型 |
| 单接口多实现问题的解决 | - Bean 名称与具体实现相同,根据名称装配; - 使用 @Qualifier 注解声明名称;- 在类上添加 @Primary 注解声明默认装配的类。 |
- @Resource 注解声明 name 字段,实现类的 @Service 注解声明 beanName。 |
| 通用解决方式 | - 将name、type存入 Map 中进行区分;- 通过 Spring 的 ApplicationContext 获取(applicationContext.getBean("<Bean名称>"))。 |
面向切面编程 AOP
动态代理机制
Spring 的 AOP 是基于动态代理实现的,将目标类的实例与调用方
JDK 动态代理
是 Spring AOP 的默认动态代理方式。
针对使用了接口的方式,在使用时调用接口类中提供的方法,执行的则是委托类的具体实现。
JDK 动态代理的实现机制是通过反射机制动态生成代码,在运行期间动态产生代理类的字节码并加载到 JVM(调用具体实现的委托类,提供给调用方)。
代码实现见此。
CGLib 动态代理
CGLib 是一个开源库,针对没有接口的情况进行动态代理,作为 JDK 动态代理的补偿。
CGLib 动态代理的实现机制是通过字节码技术为委托类生成一个代理类(该代理类实际上就是委托类的一个子类,因此不能对被 final 修饰的类进行代理)。
代码实现见此。
Bean 管理相关
Bean 创建时机
默认的 Bean 都是以单例的形式存在,默认创建的 Bean 都是在主启动类启动时加载并创建;可以使用 @Lazy 注解实现懒加载加快 IoC 的加载进度。
懒加载:被其他 Bean 引用或显式地从 BeanFactory 获取时才会加载该 Bean。
Bean 注入时机
主启动类启动时,IoC 容器将 Bean 实例化并通过默认为 setter 的注入方式,在构造函数执行后进行注入。
