Ioc 控制反转 -> 依赖 DI (依赖注入) + 容器container
Aop 切面编程 -> 依赖 proxy (动态代理)
以上两个哥们儿就构成了 Spring 框架的核心功能
Spring 中创建了一个容器, (ApplicationContext) 这个容器实质上是一个 map 它使用 key 名 管理着其中的对象
spring 启动的时候, 根据配置文件中的配置, 把配置文件的所有对象都创建好后, 放入到容器中, 当使用的时候, 就从容器中把它拿出来就可以了 classpathApplicationContext.getBean(“对象键名”) 就可以得到这个对象了
spring的配置有两种方式, 一种是XML文件方式, 另一种是注解的方式,两种方式各有优缺点
我的理解, 工具类 service DaoImpl 这些类都是相当于, 我们写好了, 只需要去调用就可以了, 这样的类就适合把它们放到容器中, 我们随时可以拿出来用, 这些别应该还有一个特点, 就是可以是一个单例.
同样, domain 或者说 pojo 中的实体类, 就不适合放在容器中, 实体类在运行过程中,会根据参数的不同而赋值不同的对象, 它们也不可能会是一个单例
我的理解, 两种方式各有优缺点, 总结一下, 如果一个这个类不怎么变动的,就会用注解方式, 如果经常变动的就使用xml, 两种配置文件是可以混用的
classPathXmlApplication 就是容器, 它的构造方法,接收一个参数, 就是 配置文件
我们在 项目的 classpath 目录下 新建一个 配置文件 applicationContext.xml
类的容器加载时, 会注入类的对象实例到容器中, 对象的属性只有两种情况, 一种是基本数据类型和字符串, 另一种是引用数据类型
同时赋值的方法, 也分两种方法来赋值, 一种是通过对象的 setter 方法来赋值, 一种是通过对象的多参构造方法来赋值
下面是其本数据类型的两种赋值方法
//上面注释的是使用类的 setter 方法赋值的, 也就是说spring会调用上面的 setter 方去对对象属性赋值
-----------------------------------------------------------------------------
<bean id="student" class="com.huang.domain.Student">
<constructor-arg name="age" value="20">constructor-arg>
<constructor-arg name="name" value="明日香">constructor-arg>
<constructor-arg name="sex" value="女">constructor-arg>
bean>
//上面的方法是使用对象的构造方法来赋值的, 也就是说对象必须有多个参数的构造方法
属性中有引用数据类据的数据的赋值方法
对例子中的student我们可以设一个学校 class School
可以看到 student类中的属性有一个是引用类型的School school , 此时如果要创建 student 对象,就必须要有 school对象
所以我们的 applicationContext.xml配置如下
<bean id="student" class="com.huang.domain.Student">
<property name="age" value="20"></property>
<property name="name" value="波多野结衣"></property>
<property name="sex" value="女"></property>
<property name="school" ref="myschool"></property>
</bean>
<bean id="myschool" class="com.huang.domain.School">
<property name="address" value="日本稻田省"></property>
<property name="name" value="稻田大学"></property>
</bean>
配置文件中, bean 是可以不分先后顺序的,都可以加载, 在student 中的引用对象 使用了 ref 来为其赋值,同时 ref的值是指向的 要使用的 bean的 id
我们在指字class的时候,使用的class的 全类名, 但是 spring 也可以智能的 根据类的类型, 或者根据类的名称来自动加载; 如下例, 我们可以在配置文件中这样写
自动装配有以下几种
no 默认的方式是不进行自动装配,通过手工设置ref 属性来进行装配bean
byName 通过参数名 自动装配,如果一个bean的name 和另外一个bean的 property 相同,就自动装配。
byType 通过参数的数据类型自动自动装配,如果一个bean的数据类型和另外一个bean的property属性的数据类型兼容,就自动装配
construct 构造方法中的参数通过byType的形式,自动装配。
default 由上级标签的default-autowire属性确定。
我们主要用的有 byName 和 byType
<bean id="student" class="com.huang.domain.Student" autowire="byName">
<property name="age" value="20">property>
<property name="name" value="波多野结衣">property>
<property name="sex" value="女">property>
bean>
<bean id="school" class="com.huang.domain.School">
<property name="address" value="日本稻田省123">property>
<property name="name" value="稻田大学123">property>
bean>
上面的配置中, 我们可以看到, bean id=student 中添加了属性 autowire = byName 使用名称自动装配
在studnet类中 private School school 属性名称为 school 所以 自动装配会找到 bean 中的 id 值也是 school 的bean 把这个 bean 自动赋值给 student.school
再来看一下 byType
<bean id="student" class="com.huang.domain.Student" autowire="byType">
<property name="age" value="20">property>
<property name="name" value="波多野结衣">property>
<property name="sex" value="女">property>
bean>
<bean id="school" class="com.huang.domain.School">
<property name="address" value="日本稻田省123">property>
<property name="name" value="稻田大学123">property>
bean>
同样的 bean student 中添加了一个 autowire的为 byType 的属性
spring 加载的时候, 会根据 student 中的 private School school 根据 school的类型, School 和 bean中的对象, 是School的类型的 自动赋值,
所以, 如果bean 文件中使用了 byType 的话, 其中如果有两个或两个以上的 School 的子类,或接口,或继承类, 也就是 如果有多个 和 school同源的类, 是会 报错的
@Component @Controller @Service @Repository
@Component在没传参的时候, 默认bean 的id 就是类名的首字母小写
这四个注解的功能大体是一样的, 都可以把类注入到容器中, 但是 @Controller @Service @Repository, 这三个又是各有个的特殊用途的
首先主配置文件的写法, 因为是使用注解引入的,所以在主配置文件中不会有配置 bean 了, 换成了扫瞄 context:component-scan base-package
<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 https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.huang.dao.impl">context:component-scan>
<context:component-scan base-package="com.huang.domain">context:component-scan>
beans>
上面的主文件扫瞄了 com.huang.dao.impl 包 和 com.huang.domain 包
那么现在我样在 ioc 容器中注入 student对象 和 school对象, 它的注解该怎么写呢?
School类的写法
package com.huang.domain;
import org.springframework.stereotype.Component;
@Component
public class School {
....
}
Student类的写法
package com.huang.domain;
import org.springframework.stereotype.Component;
@Component
public class Student {
...
}
如果我们想注入的时候指定 生成的类的 key 值, 可以写成 Component(“student1”) Component(“school1”)
上面的写法只是注入了一个类的对象, 其中的属性并没有赋值
对属性的赋值 属性的赋值注解可以写在属性的名称上, 也可以写在属性的setter方法上
分为简单类型的属性赋值和引用类型的属性赋值
对简单类型的属性赋值,我们使用 @Value(“值”)
对引用类型的属性赋值,我们使用 @Autowared @Resource 以及 @Autowared配合@Qualifter
先说简单类型
package com.huang.domain;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Student {
@Value("huangjunhui")
private String name;
@Value("20")
private Integer age;
@Value("男")
/*
@Value("天天打豆豆")
public void setName(String name) {
this.name = name;
}
*/
}
上面是使用value注解, 并且写在属性的属性名上
也可以写在setter 方法上
引用类型的注解方法
引用类型的注解也分为 byName 和 byType
其中 Spring 框架中提供了一种 注解叫 @Autowared
java的源代码中提供了一种注解叫 @Resource
它们两个可以实现同样的功能
**这里说一下两种注解的机制
@Autowared 这是Spring框架提供的一个注解, 它默认是以 byType的方式来注入对象的,如果想要以 byName的方式来注入对象, 就要把 @Autowared 和 @Qualifer(“名称”)
@ resources 是java提供的一个注解方式, 它是全自动的注入对象的,
spring将name属性解析为bean的名字,而type属性则被解析成为bean的类型,所以如果使用name属性,则使用by name的自动注入策略,如果使用type属性则使用by type的自动注入策略。如果都没有指定,则通过反射机制使用by name自动注入策略。
**
测试下
public class Student {
@Value("huangjunhui")
private String name;
@Value("20")
private Integer age;
@Value("男")
private String sex;
@Autowired
private School school;
/*
@Autowired
public void setSchool(School school) {
this.school = school;
}
*/
}
可以看到 @Autowired 写在属性上和方法上都是可以的, 这是使用的是它默认的 byType的方法, spring会检测到 要注入的属性的类型是 School 类型的, 所以就在容器中找到相应的类型进行了注入
下面使用一下 @Autowired 和 @Qulifiter(“name”)
@Autowired
@Qualifier("school1")
public void setSchool(School school) {
this.school = school;
}
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("school1")
public class School {
@Value("北大")
public String name;
@Value("北京海淀")
public String address;
}
我们把 class School 上的 Component(“school1”) 说明了, 当注入时 school1,就是注入的对象的名称
同时, 我们在 Student 类的 getSchool 方法上 使用了 @Autowired 和 @Qualifter(“school1”) ,也就是使有byName 的方式, 指定了注入名称为 school1的对象
使用 @resource 方式注入
@resource的执行方式
如果 @resource 没有name属性 ,则会使的属性的名称做为 name的值去查找 bean的id , 如果没有找到,就使用 byType再操作一次,如果都没有找到, 则报错
如果 @resource 的name属性有值, 则按 name 的值去查找 bean的id , 找到就赋值,找不到就报错
当然, @Resource 也可以有 type属性,不再多说了
以上就是 Spring的 IoC 的配置方式, 下一节要说 Spring 的 Aop