IOC: 就是控制反转
-----------
原来是自己创建对象,现在交给spring容器创建对象
Spirng创建对象的原理:
--------------
加载核心配置文件 逐行解析xml文件 当解析到bean时开始创建对象(利用反射创建对象) 将创建好的对象存入map中 key就是id
Spring容器获取对象的方式:
----------------
配置文件的写法:`<bean id=" " class=" "> <bean/>
(1)通过ID获取对象
context.getBean(" id ");
(2)通过class类型获取对象(风险)
context.getBean( 类名.class);
因为spring以map的形式存储对象,可以有重复的value 当value的值相同时就会报异常
Spring创建对象的四种方式:
----------------
(1)无参构造创建对象: 是以反射方法
要有一个无参构造方法,当类中不写无参构造时,系统默认创建一个无参构造,如果要自己写构造方法,必须添加一个无参构造方法
(2)静态工厂
当对象不能通过反射直接创建时,就用静态工厂的方法
配置文件中的写法:
<bean id=" " class=" " factory-method=" 静态方法 " />
(3)实例工厂
factory-bean=“ ” factory—method=“方法”
一般使用通过对象.方法 获取一个对象 时使用
<bean id="" class=""/>
<bean id="" factory-bean=“ ” factory—method=“方法”>
(4)Spring工厂 实现FactoryBean接口 通过里面的getObject()
单例和多例:
------
单例对象是如何存储?
单例对象一般是存放在Spring的map集合中,和Spring容器同生共死
多例对象是如何存储?
多例对象默认为懒加载,用户每调用一次对象Spring容器就会创建一个对象 ,Spring对象不负责维护多例对象的生命周期,谁调用谁负责.
通过scope改变单例和多例。
懒加载机制:
------
两种方法:
全局配置懒加载生效:default-lazy-init="true"
局部配置懒加载生效:
lazy-init="false" 不生效
lazy-init="true" 生效
lazy-init="default" 看全局的 如果没有全局 就默认不生效
DI 依赖注入
-------
1.set方法注入
类中必须有set方法,配置文件中通过property为属性赋值 name的获取方法: 去掉set 将紧跟的后面的字母变为小写
(1)简单类型:
(2)集合:
(3)配置文件:具体代码如下
```
<bean id="user" class="pojo.User" >
<!--为简单属性赋值 -->
<property name="id" value="100"/>
<property name="name" value="孙尚香"/>
<!--为集合赋值 -->
<property name="list"> <!--ArrayList -->
<list>
<value>上单</value>
<value>中单</value>
<value>打野</value>
<value>射手</value>
<value>肉盾</value>
</list>
</property>
<property name="set">
<set>
<value>一</value>
<value>一</value>
<value>二</value>
</set>
</property>
<property name="map">
<map>
<entry key="1" value="1"/>
<entry key="2" value="2"/>
<entry key="3" value="3"/>
</map>
</property>
<!--为配置文件赋值-->
<property name="pro">
<props>
<prop key="一">一</prop>
<prop key="二">二</prop>
<prop key="三">三</prop>
</props>
</property>
</bean>
```
(4)引用
两个步骤:
(1)先将对象创建出来
(2)添加引用
```
<bean id="cat" class="pojo.Cat"></bean>
<bean id="user" class="pojo.User" >
<!-- ref="" 表示对象的引用 -->
<property name="dog" ref="dog"/>
</bean>
```
2.构造方法注入
必须写构造方法,先写无参构造.代码如下:
```
构造方法为:
//3个参数构造
public User(Integer id, String arg0, Dog dog) {
super();
this.id = id;
this.name = arg0;
this.dog = dog;
}
配置文件为:
<!--构造方法注入 3个参数 -->
<bean id="user" class="pojo.User">
<!--代表一个参数
index="0" 参数的下标 从0开始
name="" 参数名称
ref="" 对象的引用
value="" 属性的值
-->
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="王者荣耀"/>
<constructor-arg index="2" name="dog" ref="dog"/>
</bean>
```
注入方式分析:
程序员自己写的代码set注入较多,如果是软件架构使用构造注入居多
注意:
(1)构造函数中参数一定要和配置文件中的参数个数相同,否则会报could not resolve constructor异常
(2)当没有导包的时候,java中不会维护形参的名称,所以使用name属性进行注入时,会发生风险,所以用index进行注入
对象注入简化:
------------
autowire标签 自动装配,为引用类型自动赋值.需要一来set方法,也就是说类中必须有set方法!
分为两种方式:
autowire="byName" 实现原理:
1.找到当前对象的set方法
2.将方法进行变形 将set去掉 首字母换成小写
3.通过变形后的名字找到bean中所有的id,如果一致就能成功注入
4.如果根据id进行匹配,如果没有成功,不能入住,为null,有风险,不建议
autowire="byType" 实现原理:
1.找到当前对象的set方法
2.找到参数类型
3.根据class匹配bean中class 如果找到就注入成功,否则就返回null;
```
代码实现:一般在约束标签中添加,省去了<property name="dog" ref="dog"/>
default-autowire="byType"
```
属性注解
---------
优点:省去了对象的注入标签,在类中的引用对象中添加属性注解,省去了对象注入简化.
实现方法:在配置文件中添加
```
<!--开启属性注解 -->
<context:annotation-config/>
```
分类:
(1) @Autowired注解
实现原理:
Autowired注解有两种装配方式为byName,byType. 根据指定的对象的匹配bean中id,如果成功
则成功,如果失败根据class类型匹配 都失败证明bean中没有指定的数据,报错,Spring容器启动
失败,给用户更好的体验,报出的异常如下图所示:
```
//代码实现:
@Autowired
private Dog dog;
@Autowired
private Cat cat;
```
(2)为了解决上面的问题,引入一个标签@Qualifier(value="id名字")为指定id进行注入
注意点:
```
@Autowired //两个注解都是spring提供的
@Qualifier(value="dogB") //表示强制指定ID进行注入 2个注解必须一起使用,否则报错
private Dog dog;
```
(3)@Resource 注解 综合了以上两种的优点可以直接指定id注入
```
//代码实现:
@Resource(name="dogA")
private Dog dog;
```
说明:
1.如果是单个项目使用任意一个都可以
2.如果是多个项目,则使用@Autowired
类的注解 @component
目的:为了省去配置文件中的<bean>标签
实现方法:
在配置文件中添加
```
<!--开启包扫描
base-package="pojo" 指定的包路径
如果包的个数较多,使用“,”号分割
只要给定了包路径,就会扫描给定包的全部子孙包
只要开启包扫描 默认开启属性注解
-->
<context:component-scan base-package="pojo"/>
//在类中添加
@Component
public class User {
@Autowired
private Dog dog;
}
同类型的注解:
@Scope(value="protoType") //对象的单例和多例
@Lazy(true) //表示懒加载
@Component //万能注解
@Controller //控制层的注解
@Service //业务层注解
@Repository //持久层的注解
功能上和@Component没有任何差别,为了让程序员编程更加的明确,定义的。
@Component(value="tom") 指定Bean的Id为tom
注解的使用原理:
1.当容器启动时,首先会加载spring的配置文件。
2.根据包扫描指定的包路径spring会扫描当前包下的全部子孙包
3.在扫描时如果发现类上还有@Component注解,则会根据spring的规则为其创建对象。将对象创建通过反射创建完成后,存入spring所维护的map中,key就是类名首
字母小写。value就是生成的对象。则会发出报错信息。容器启动失败。
4.如果类中需要进行对象注入则在创建对象的之后,自动的根据注解的匹配规则为其注入正确的对象,如果对象正确注入。则spring返回正确的对象如果注入有误,
spring则会发出报错信息。容器启动失败。
ID生成策略
默认规则:看类名字的第二个字母,当第二个字母为大写时,则保持类名不变,如果第二个字母小写,类名的首字母才会小写
回显bean中的id
实现接口BeanNameAware
//代码实现:
public class Test implements BeanNameAware{
@Override
public void setBeanName(String name) {
System.out.println("当前bean的id为"+name);
}
}
为属性赋值
=====
为基本类型赋值
```
@Value("100")
private Integer id;
```
为基本类型动态赋值:
<context:property-placeholder location="classpath:/配置文件的名字"/>
//类里面:
@Value("${ 配置文件中的key}")
private String name;
//配置文件xxx.properties的写法:
key=value
为集合赋值
引入约束条件util
定义集合
属性引入:
//配置文件的写法
<util:list id= "list">
<value>1</value>
<value>2</value>
<value>3</value>
</util:list>
//属性引入:
@Value("#{list}")//注意和基本类型动态赋值的区别
private List list;
“`