IoC(Inverse of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。不过,IoC 并非 Spirng 特有,在其他语言中也有应用。
为什么叫控制反转?
DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
理解 DI 的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
●谁依赖于谁:当然是应用程序依赖于IoC容器;
●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
●谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
IoC 和 DI 由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对 IoC 而言,“依赖注入”明确描述了“被注入对象依赖 IoC 容器配置依赖对象”。
(原文地址:http://jinnianshilongnian.iteye.com/blog/1413846)
xml解析、工厂模式、反射
1). Spring 框架的核心是 Spring 容器。容器创建对象,将它们装配在一起,配置它们并管理它们的完整生命周期。Spring 容器使用依赖注入来管理组成应用程序的 组件。容器通过读取提供的配置元数据来接收对象进行实例化,配置和组装的指令。该元数据可以通过 XML,Java 注解或Java 代码提供。
2). IOC 思想是基于 IOC 容器完成的,IOC 容器的底层就是对象工厂。
3). Spring 提供IOC容器的两种实现方式:
(a). BeanFactory:IOC 容器的基本实现,是 Spring 内部的使用接口,不提供开发人员使用。
? ? ? ? ? ? ?( 加载配置文件的时候不会创建对象,在获取对象的时候才去创建对象。)
(b). ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能一般由开发人员进行使用。
? ? ? ? ? ? ?( 加载配置文件的时候就会创建对象。)
3). ApplicationContext的主要实现类:
(a). ClassPathXmlApplicationContext
(b). FileSystemXmlApplicationContext
1). 什么是 Bean
简单来说,bean 代指的就是那些被 IoC 容器所管理的对象。
我们需要告诉 IoC 容器帮助我们管理哪些对象,这个是通过配置元数据的定义的。配置元数据可以是 XML 文件、注解或者 Java 配置类。
2). bean 的作用域
Spring 中 Bean 的作用域通常由下面几种:
singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的,对单例设计模式的应用。
prototype : 每次请求都会创建一个新的 bean 实例。
request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。
global-session : 全局 session 作用域,仅仅在基于 portlet 的 web 应用中才有意义,Spring5 已经没有了。Portlet 是能够生成语义代码(例如:HTML)片段的小型 Java Web 插件。它们基于 portlet 容器,可以像 servlet 一样处理 HTTP 请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。
2). bean 的生命周期
Bean 容器找到配置文件中 Spring Bean 的定义。
Bean 容器利用 Java Reflection API 创建一个 Bean 的实例。
如果涉及到一些属性值 利用 set()方法设置一些属性值。
如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入 Bean 的名字。
如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。
如果 Bean 实现了 BeanFactoryAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoade r 对象的实例。
与上面的类似,如果实现了其他 *.Aware接口,就调用相应的方法。
如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessBeforeInitialization() 方法
如果 Bean 实现了InitializingBean接口,执行afterPropertiesSet()方法。
如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法
当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法
Bean管理指的是两个操作
1). Spring 创建对象
2). Spring 注入属性
1). 基于 xml 配置文件方式实现
2). 基于注解方式实现
<bean id="user" class="com.atguigu.spring5.User"></bean>
1). 在 Spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建。
2). bean 标签的常用属性:
id 属性:唯一标识
class 属性:类的全路径
3). 创建对象的时候,默认是执行无参数的构造方法来完成创建对象。
也就是依赖注入,注入属性
1). 第一种注入方式:使用 set 方法注入
(a). 创建类的时候定义属性,并且定义属性对于的 set 方法。
public class Book {
//创建属性
private String bName;
//创建属性对应的set方法
public void setBname(String bName) {
this.bName = bName;
}
}
(b). 在 Spring 配置文件配置对象创建,并且配置属性注入。
<bean id="book" class="com.atguigu.spring5.Book">
<!--使用property完成属性注入
name:类里面属性名称
value:向属性注入的值
-->
<property name="bName" value="Hello"></property>
</bean>
2). 第二种注入方式:使用构造函数进行注入
(a). 创建类,定义属性,然后创建带有属性参数的构造方法
public class Orders {
//属性
private String oName;
private String address;
//有参数构造
public Orders(String oName,String address) {
this.oName = oName;
this.address = address;
}
}
(b). 在 Spring xml 配置文件中进行配置
<bean id="orders" class="com.atguigu.spring5.Orders">
<constructor-arg name="oname" value="Hello"></constructor-arg>
<constructor-arg name="address" value="China!"></constructor-arg>
</bean>
3). p 名称空间注入
使用 p 名称空间注入,需要添加p名称空间在配置文件中,然后在bean标签里面进行操作。
<!--1、添加p名称空间在配置文件头部-->
<?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:p="http://www.springframework.org/schema/p" <!--在这里添加一行p-->
<!--2、在bean标签进行属性注入(算是set方式注入的简化操作)-->
<bean id="book" class="com.atguigu.spring5.Book" p:bname="very" p:bauthor="good">
</bean>
4). 注入空值和特殊符号
<bean id="book" class="com.atguigu.spring5.Book">
<!--null值-->
<property name="address">
<null/><!--属性里边添加一个null标签-->
</property>
<!--特殊符号赋值-->
<!--属性值包含特殊符号
a 把<>进行转义 < >
b 把带特殊符号内容写到CDATA
-->
<property name="address">
<value><![CDATA[<<南京>>]]></value>
</property>
</bean>
5). 注入属性-外部 bean
(a). 创建两个类 service 和 dao 类
public class UserService {//service类
//创建UserDao类型属性,生成set方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add() {
System.out.println("service add...............");
userDao.update();//调用dao方法
}
}
public class UserDaoImpl implements UserDao {//dao类
@Override
public void update() {
System.out.println("dao update...........");
}
}
(b). 在 spring 配置文件中进行注册
<!--service和dao对象创建-->
<bean id="userService" class="com.atguigu.spring5.service.UserService">
<!--注入userDao对象
name属性:类里面属性名称
ref属性:创建userDao对象bean标签id值
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>
6). 注入属性-内部 bean
一对多关系:部门和员工
一个部门有多个员工,一个员工属于一个部门(部门是一,员工是多)
在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示。
//部门类
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
}
//员工类
public class Emp {
private String ename;
private String gender;
//员工属于某一个部门,使用对象形式表示
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
}
然后在配置文件中进行配置
<!--内部bean-->
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="Andy"></property>
<property name="gender" value="女"></property>
<!--设置对象类型属性-->
<property name="dept">
<bean id="dept" class="com.atguigu.spring5.bean.Dept"><!--内部bean赋值-->
<property name="dname" value="宣传部门"></property>
</bean>
</property>
</bean>
也可以级联赋值
a. 方式一:
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="Andy"></property>
<property name="gender" value="女"></property>
<!--级联赋值-->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
<property name="dname" value="公关部门"></property>
</bean>
b.方式二:
需要生成属性的 get 方法
public Dept getDept() {
return dept;
}
然后再配置文件中进行配置
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="jams"></property>
<property name="gender" value="男"></property>
<!--级联赋值-->
<property name="dept" ref="dept"></property>
<property name="dept.dname" value="技术部门"></property>
</bean>
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
</bean>
7). 注入集合属性
(a). 注入数组类型
(b). 注入 List
(c). 注入 Map
(d). 注入 Set
1.创建类,定义4种类型属性,生成对应 set 方法
public class Stu {
//1 数组类型属性
private String[] courses;
//2 list集合类型属性
private List<String> list;
//3 map集合类型属性
private Map<String,String> maps;
//4 set集合类型属性
private Set<String> sets;
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
2.在 spring 配置文件进行配置
<bean id="stu" class="com.atguigu.spring5.collectiontype.Stu">
<!--数组类型属性注入-->
<property name="courses">
<array>
<value>java课程</value>
<value>数据库课程</value>
</array>
</property>
<!--list类型属性注入-->
<property name="list">
<list>
<value>张三</value>
<value>小三</value>
</list>
</property>
<!--map类型属性注入-->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<!--set类型属性注入-->
<property name="sets">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
</bean>
1). 注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)
2). 使用注解,注解作用在类上面,方法上面,属性上面
3). 使用注解目的:简化 xml 配置
下面四个注解功能是一样的,都可以用来创建 bean 实例
@Component
@Service
@Controller
@Repository
1). 先引入依赖,然后在 Spring 配置文件中开启注解扫描
<!--开启组件扫描
1 如果扫描多个包,多个包使用逗号隔开
2 扫描包上层目录
-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
2). 创建类,在类上面添加创建对象注解
//在注解里面 value 属性值可以省略不写,
//默认值是类名称,首字母小写
//UserService -- userService
@Component(value = "userService") //注解等同于XML配置文件:<bean id="userService" class=".."/>
public class UserService {
public void add() {
System.out.println("service add.......");
}
}
<!--示例 1
use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter
context:include-filter ,设置扫描哪些内容
-->
<context:component-scan base-package="com.atguigu" use-defaultfilters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/><!--代表只扫描Controller注解的类-->
</context:component-scan>
<!--示例 2
下面配置扫描包所有内容
context:exclude-filter: 设置哪些内容不进行扫描
-->
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/><!--表示Controller注解的类之外一切都进行扫描-->
</context:component-scan>
1). @Autowired:根据属性类型进行自动装配
@Service
public class UserService {
//定义 dao 类型属性
//不需要添加 set 方法
//添加注入属性注解
@Autowired
private UserDao userDao;
public void add() {
System.out.println("service add.......");
userDao.add();
}
}
//Dao实现类
@Repository
//@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("dao add.....");
}
}
2). @Qualifier:根据名称进行注入,这个@Qualifier 注解的使用,和上面@Autowired 一起使用
//定义 dao 类型属性
//不需要添加 set 方法
//添加注入属性注解
@Autowired //根据类型进行注入
//根据名称进行注入(目的在于区别同一接口下有多个实现类,根据类型就无法选择,从而出错!)
@Qualifier(value = "userDaoImpl1")
private UserDao userDao;
3). 可以根据类型注入,也可以根据名称注入(不推荐使用)
//@Resource //根据类型进行注入
@Resource(name = "userDaoImpl1") //根据名称进行注入
private UserDao userDao;
4). @Value:注入普通类型属性
@Value(value = "abc")
private String name
编写一个配置类,实现 @Configuration 和 @ComponentScan 注解来替代xml配置文件
@Configuration //作为配置类,替代 xml 配置文件
@ComponentScan(basePackages = {"com.atguigu"})//开启注解扫描
public class SpringConfig {
}
然后编写一个测试类
@Test
public void testService2() {
//加载配置类
ApplicationContext context
= new AnnotationConfigApplicationContext(SpringConfig.class);//注意里使用了AnnotationConfigApplicationContext
UserService userService = context.getBean("userService",
UserService.class);
System.out.println(userService);
userService.add();
}
原文:https://www.cnblogs.com/zeliCode/p/15142346.html