Ioc容器,我们最常使用的就是依赖注入方式了,也是为了解耦,刚开始其实觉得这个解耦主要是解开了创建对象这个步骤,减少了代码的重复性,将各个模块可以相对没有适用spring之前那样减少相互的依赖,相对便利,后面经过使用次数的增多以及阅览相关资料的篇幅逐渐增加,开始慢慢理解IOC模型的好处,它并不是启动的时候就将配置文件或者注解等元信息和JavaBean的类信息加载到IOC容器并根据配置创建模型,而是根据是否调用,再来像机械装配一样,以配置好的形式创建并注入(或者说创建)到需要并且属于扫描区域(或setter方法中)的应用类中。不常用的依赖查找就不在这里提及了。
鉴于之前已经提及了spring的依赖注入,那么直接上例子。
源码传送门,1.4部分,讲解注入
目录
一、延迟加载
二、单例多例
三、依赖注入
1、通过构造方法进行依赖注入
xml(普通字符串)
普通javaBean
用于注入的javaBean
注入xml(注入javaBean)
测试类
2.通过setter的方法进行依赖注入(推荐)
xml(普通字符串)
javaBean
注入JavaBean
xml注入javaBean
测试方法
3、基于命名空间
p-namespace (property)
c-namespace (constructor-arg)
四、@Lookup注入
方式一
方式二
默认情况下,不是延迟加载,加载完配置后,已经创建完对象
如果配置了延迟加载,单例用到的时候才创建,且只创建一次
default : 默认值 false,不是延迟加载
false: 不是延迟加载
true: 代表延迟加载,使用到这个类的时候再去创建对象
默认为单例模式,如果为多例,则设置延迟加载为false失效,即必须延迟加载
scope="prototype">
* 1、singleton:单例(默认情况下是单例 )
* 2、prototype:多例
* 3、request:一个请求一个实例
* 4、session:一个回话一个实例
一般只有在Action也就是视图层才会用到多例
下文所用的xml文档,统一使用 applicationContext_DI.xml 放置于src目录下,不再提及。
web.xml
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
classpath:config/applicationContext_*.xml //配置文件所在位置
构造方法注入--无参构造
public class Student {
//注入的普通的参数String+8大类型
private String name;
//无参的构造方法最好放回来
public Student(){
}
//通过我们有参构造方法进行依赖注入
public Student(String namesss){
this.name = namesss;
}
public String toString() {
return "Student [name=" + namesss};
}
构造方法注入---注入javaBean
public class Score {
private Integer score;
//通过有参的构造方法注入分数
public Score(Integer score) {
super();
this.score = score;
}
public Score() {
super();
}
@Override
public String toString() {
return "Score [score=" + score + "]";
}
public void test1(){
ApplicationContext context =
new ClassPathXmlApplicationContext("config/applicationContext_DI.xml");
Student s = (Student)context.getBean("s1");
System.out.println(s);
}
setter方法注入----普通字符串
public class Admin {
private String name;//字符串
//提供相应的setter的方法
public void setNameStr(String name) {
this.name = name;
}
setter注入----注入javaBean
public class Gender {
//通过setter的方法注入普通的字符串
private String gender;
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Gender [gender=" + gender + "]";
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/applicaionContex.DI.xml");
Object b = context.getBean("zz");
System.out.println(b);
}
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
主要针对已经单例的实例A中与其他实例B组合,B需要多个实例的情况。
引入ApplicationContext每次调用方法时用上下文的getBean(name,class)方法去重新获取bean B的实例。
正如官方文档例子 则过于耦合代码
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext = null;
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
protected Command createCommand() {
// notice the Spring API dependency!
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(
ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
使用@Lookup 注解注入
public abstract class CommandManager {
public Object process(Map commandState) {
// grab a new instance of the appropriate Command
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
@Lookup
protected abstract Command createCommand() ;
}
Tips: 被注入的方法需要满足以下格式
[abstract] theMethodName(no-arguments);
lookup代码示例地址
这样获取的内部实例就会满足我们的需求
ps:在翻查笔记的过程中,当时居然还写了一些spring2.5,3.0的新特性----简化setter方法的注入,其实本人觉得好像意义不大,下篇带过