IOC
一: 相关概念
-
耦合:
是对模块间关联度的表示,耦合的强弱取决于模块间接口的复杂性,调用模块的方式以及通过界面传输数据的多少。
耦合度
是指项目模块之间的依赖关系,包括控制关系,调用关系,数据传输关系。模块间联系越多,耦合度越高,独立性越差,同时项目的维护成本就越高,所以项目中的设计时应当注意减小类之间耦合度。- 分类:
- 内容耦合: 一个模块直接修改另一模块的数据,或者一个模块通过非正常入口进入另一模块
- 公共耦合: 两个或两个以上的模块共同引用一个全局数据
- 外部耦合: 多个模块都访问同一全局变量而不是同一全局数据结构,且不是通过参数传递该全局变量的信息
- 控制耦合: 一个模块通过接口想另一个模块传递一个控制信号,接受信号的模块根据信号进行活动
- 标记耦合: 一个模块通过一个接口想两个模块传递一个公共参数,那么这两个模块间是标记耦合
- 数据耦合: 模块之间通过参数来传递数据,被称为数据耦合
- 非直接耦合: 两个模块之间没有直接关系,他们之间的联系完全是通过主模块的控制和调用来实现的
- 分类:
-
解决耦合的思路
- 通过反射创建
在jdbc中,通过反射注册驱动,这样可以使类不再依赖具体的驱动类,即使删除jar包,依然可以编译(但不能运行),可以通过配置文件配置mysql驱动的全限定类名字符串
Class.forName("com.mysql.jdbc.Driver");
-
控制反转 IOC
控制反转 (Inversion of Control,缩写为IoC) 是面向对象变成的一种设计原则,可以减低代码间的耦合度,其中最常见的方式叫做依赖注入(Dependency Injection,简称DI)。
之前获取对象时,都是使用new的方式,是主动去创建对象。而通过控制反转,让对象在被创建的时候,由一个控制系统内所有对象的外界实体进行管理,将其所依赖的对象的引用传递给它是被动的。
二: IOC基础入门
-
mavend依赖
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5 RELEASE</version> </dependency> </dependencies>
-
调用
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); MyUser myuser = (MyUser)ac.getBean("MyUser");
三: IOC:基于XML操作
-
在类的根目录(resources)下创建配置文件 .xml
可以从官方源码文件中获取文档查询相应文件头: 下载地址:https://repo.spring.io/release/ 文档地址: spring-framework-5.2.5.RELEASE\docs\spring-framework-reference\index.html
<?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:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd"> <!-- bean definitions here --> </beans>
-
配置
<bean>
标签<!-- bean 标签:用于配置让 spring 创建对象,并且存入 ioc 容器之中 id 属性:对象的唯一标识。 class 属性:指定要创建对象的全限定类名 scope 属性: 声明bean对象的作用范围 scope="singleton" : 单例对象(默认) 生命周期 : 创建 : 当容器创建时对象创建 使用 : 容器还在,对象就一直存活 销毁 : 容器销毁,对象销毁 scope="prototype" : 多例对象 创建 : 当使用对象时,spring框架创建 使用 : 对象只要是在使用过程中就一直存活 销毁 : 当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收 scope="request" : 作用于web应用的请求范围 scope="session" : 作用域web应用的会话范围 scope="global-session" : 作用域集群环境的会话范围(全局会话范围),不是集群环境时,就是session init-methos 属性: bean创建时执行 destory-methos 属性:bean销毁时执行 --> <bean id="MyUser" class="com.cccq.domain.MyUser"> </bean>
-
获取使用bean对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); MyUser myuser = (MyUser)ac.getBean("MyUser"); //MyUser myuser = ac.getBean("MyUser", MyUser.class);
-
BeanFactory 和 ApplicationContext 的区别
-
ApplicationContext : 在构建核心容器时,创建对象采取的方式是立即加载方式。一读取完配置文件就马上使用反射方式将配置文件中的配置对象创建出来
- 更适合单例对象
- ClassPathXmlApplicationContext : 可以加载类路径下的配置文件,要求配置文件必须在类路径下
- FileSystemXmlApplicationContext : 可以加载磁盘任意路径下的配置文件,但是必须有访问权限
- AnnotationConfigApplicationContext : 用于读取注解创建容器的
-
BeanFactory : 在构建核心容器时,创建对象采取的方式是延迟加载方式。根据什么时候根据id获取对象,什么时候才会真正创建对象
- 更适合多例对象
-
-
-
创建bean对象的三种方式
-
默认无参构造器创建bean
-
在默认情况下,会根据默认的无参构造函数创建对象,如果bean类中没有默认的无参构造函数,将会创建失败
<bean id="MyUser" class="com.cccq.domain.MyUser"></bean>
-
-
静态工厂方法创建bean
-
使用工厂中的静态方法创建对象,使用某个类中的静态方法创建对象,需要指定class属性,并存入spring容器中
<bean id="MyUser" class="com.cccq.domain.MyUser" factory-method="staticMethod"></bean>
-
属性:
- id :指定 bean 的 id,用于从容器中获取
- class :指定静态工厂的全类名
- factory-method :指定生产对象的静态方法
-
-
实例工厂方法创建bean
-
将工厂的创建交给spring进行管理,然后在使用工厂的bean来调用里面的方法,不能指定class属性
<!-- CreateUserz中createMyUser方法返回一个MyUser对象 --> <bean id="CreateUser" class="com.cccq.domain.CreateUser"></bean> <bean id="MMyUser" factory-bean="CreateUser" factory-method="createMyUser"></bean>
-
参数:
- factory-bean :用于指定实例工厂 bean 的 id。
- factory-method :用于指定实例工厂中创建对象的方法。
-
-
-
依赖注入(DI)
依赖注入(Dependency Injection) 是spring中ioc的具体实现,在spring中,IOC是通过控制反转将创建对象的控制权交给spring。而DI是spring容器将某个依赖关系注入到spring创建的对象中,提升组件的复用性
-
构造函数注入
-
使用类中的构造函数,给成员变量进行赋值 (如果是经常变化的数据,并不适用于注入方式
<bean id="MyUser" class="com.cccq.domain.MyUser"> <constructor-arg name="name" value="username"></constructor-arg> </bean>
-
特点 : 在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功
- 标签 : constructor-arg
- 位置: bean标签内部
- 属性: (上三个是用于指定给构造函数中指定名称的参数赋值)
- type : 用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
- index : 用于指定要注入的数据给构造函数中指定索引位置的参数赋值,索引的位置是从0开始
- name : 用于指定给构造函数中指定名称的参数赋值
- value : 用于提供基本类型和String类型的数据
- ref : 用于指定其他的bean类型数据,指的就是在spring的容器中出现过的bean对象
-
-
setter方法注入 (更常用)
-
在类中需要提供成员的set方法
<bean id="MyUser" class="com.cccq.domain.MyUser"> <property name="name" value="username"></property> </bean>
-
特点 : 创建对象时没有明确限制,可以直接使用默认构造函数,但是如果某个成员必须有值,则获取对象时可能set方法没有执行
- 涉及标签 :
- 位置: bean标签内部
- 属性:
- name : 用于指定给构造函数中指定名称的参数赋值 (不在意属性名,只在意set方法名,setName->name)
- value : 用于提供基本类型和String类型的数据
- ref : 用于指定其他的bean类型数据,指的就是在spring的容器中出现过的bean对象
-
-
p命名空间注入
- 通过在xml中导入p名称空间,使用 p:propertyName 来注入数据,其本质仍然是调用类中的set方法来实现注入功能
-
使用时需要在xml头部配置
-
xmlns:p=“http://www.springframework.org/schema/p”
<bean id="MyUser" class="com.cccq.domain.MyUser" p:name="username" p:sex-ref="boy"/>
-
-
属性:
- p:属性名 : 指定注入的参数属性名并进行赋值
- p:属性名-ref : 被注入的bean的id
-
注入集合属性
- 给类中的集合成员传值,使用的也是set方法注入的方式,不过变量的数据类型都是集合
-
Array,List,Set,Map,Properties
<bean id="MyUser" class="com.cccq.domain.MyUser"> <property name="MyArray"> <array> <value>Array1</value> <value>Array2</value> </array> </property> <property name="MyList"> <list> <value>List1</value> <value>List2</value> </list> </property> <property name="MySet"> <set> <value>Set1</value> <value>Set2</value> </set> </property> <property name="MyMap"> <map> <entry key="mapKey1" value="mapValue1"></entry> <entry key="mapKey2"> <value>mapValue2</value> </entry> </map> </property> <property name="MyProps"> <props> <prop key="propKey1">propValue1</prop> <prop key="propKey2">propValue2</prop> </props> </property> </bean>
-
用于给Liet结构集合注入的标签:
- array,list,set,
-
用于给Map结构集合注入的标签
- map,props
-
结构相同,标签可以互换
-
接口注入 (使用较少,一般不推荐)
- 需要调用者实现一个指定的接口,需要强制被注入对象实现不必要的接口
-
四: IOC:基于注解操作
-
明确
- 注解配置和 xml 配置要实现的功能是一样的,都可以降低程序间的耦合,只是配置的形式不一样
.xml 配置文件中的配置 ->需要 xmlns:context 文件头
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 告知spring创建容器时需要扫描的包, --> <context:component-scan base-package="com.cccq"></context:component-scan> <!-- <context:annotation-config/> --> </beans>
-
常用注解
-
创建对象
作用和在XML配置文件中编写一个标签实现的功能时一样的 @Controller,@Service,@Repository 都是针对@Component的衍生注解,他们的作用及属性都是一模一样的,只是为了三层架构更加清晰
-
@Component() :用于把当前类对象存入spring容器中
-
@Controller() : 一般用于表现层的注解
- @Service() : 一般用于业务层的注解
-
@Repository() : 一般用于持久层的注解
- 作用: 用于把当前类对象存入spring容器中
- 属性:
- value: 指定bean的id,如果不指定value属性,默认id是当前类的类名,首字母小写
-
-
注入数据
作用和在XML配置文件中的标签中写一个标签的作用时一样的 @Autowried,@Qualifier,@Resource 都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现,需使用@Value 另外,集合类型注入只能使用XML来实现
-
@Autowired :
- 作用 : 按照类型注入,只要容器中有唯一一个bean对象类型和要注入的变量类型匹配,就可以注入成功;如果IOC容器中没有任何bean的类型和要注入的变量类型匹配,则报错;如果IOC容器中有多个类型匹配时,首先按照类型圈定匹配的对象,然后再使用变量名称作为bean的id作为key去查找,如果有就注入成功
- 位置 : 可以在变量上,也可以在方法上
- 细节 : 在使用注解注入时,set方法不是必须的,首先按照变量类型去匹配
-
@Qualifier() :
- 作用 : 在按照类中注入的基础上在按照bean的id注入,在给属性字段注入时不能独立时使用,必须和@Autowried一起使用;但是给方法参数注入时,可以独立使用(@@Qualifier("引用的bean的Id"))
- 属性 :
- value :指定bean的id
-
@Resource() :
- 作用 : 直接按照bean的id进行注入,可以独立使用
- 属性 :
- value :指定bean的id
-
@Value() :
- 作用 : 注入基本类型和String类型数据
- 属性 :
- value:用于指定值,可以使用spring中的SpEL(Spring的el表达式)
- SpEL的写法: ${表达式}
- value:用于指定值,可以使用spring中的SpEL(Spring的el表达式)
-
-
改变作用范围
作用和在标签中使用scope属性是一样的
- @Scope :
- 作用 : 用于指定bean的作用范围
- 属性 :
- value :是定范围的取值
- singleton : 单例
- prototype : 多例
- value :是定范围的取值
- @Scope :
-
生命周期
作用和在标签中使用init-method和destory-method的作用是一样的
-
@PostConstruct :
- 作用 : 用于指定初始化方法
-
@PreDestroy :
- 作用 : 用于指定销毁方法
-
-
-
纯注解配置
与XML配置文件中的内容功能相同
-
@Configuration
- 作用 : 用于指定当前类是一个spring配置类,被注解的类内部包含一个或者多个被@Bean注解的方法,这些方法会被AnnotationConfigApplicationContext类进行扫描构建bean,初始化spring容器
- 位置 : 在类名上
- 细节 : 当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该配置可以不写
-
@ComponentScan()
- 作用 : 用于通过注解指定spring在创建容器时要扫描的包
- 属性 :
- value : 他和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包(使用此注解等同于在xml中配置了<context:component-scan base-package="com.cccq"/>)
- 位置 : 在类名上
-
@Bean()
- 作用 : 只能写在方法上,表名用此方法创建一个对象,并且放入spring容器中
- 属性 :
- name : 给当前被@Bean注解的方法创建的对象指定一个名称 (等同于bean的id) ,不写时默认是当前方法名
- 细节 : 当使用注解配置方法时,如果方法有参数,spring回去容器中查找有没有对应的bean对象,查找方式和
@Autowired
注解的作用时一样的
-
@PropertySource()
- 作用 : 用于加载
.properties
文件中的配置, - 属性 :
- value[] : 用于指定properties文件的位置,如果是在类路径下,需要写为classpath:包名/文件名.properties
- 作用 : 用于加载
-
@Import()
- 用于导入其他配置类,在引入其他配置类时,可以不用再写
@Configuration
注解 - 属性 :
- value[] : 用于指定其他配置类的字节码 (config.class)
- 用于导入其他配置类,在引入其他配置类时,可以不用再写
-
在纯注解下获取容器
- AnnotationConfigApplicationContext类
ApplicationContext ac = new AnnotationConfigApplicationContext(spring配置类.class);
-