IOC概念和原理
什么是IOC
通过图片了解IOC底层原理
弊端:耦合度太高了
目的:耦合度降低最低限度
IOC过程
IOC(接口)
- IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
- spring提供了IOC容器实现的两种方式:(两个接口)
- BeanFactory
- IOC容器基本实现,是spring内部的使用接口,不提供开发人员使用
- 加载配置文件的时候不会创建对象,在获取对象或者使用对象的时候才去创建对象
- ApplicationContext
- BeanFactory接口的子接口,提供了更多更强大的功能,一般由开发人员使用
- 在配置文件的时候就会把在配置文件中的对象进行创建,将耗时耗资源的事都交给服务器完成
- BeanFactory
- ApplicationContext接口有实现类

FileSystemXmlApplicationContext
调用的事磁盘路径
ClassPathXmlApplicationContext
调用的是路径
IOC操作Bean管理
什么是Bean管理
Bean管理指的是两个操作
在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
- 在bean标签有很多属性,介绍常用的属性
- id:唯一标识
- class:类的全路径(包和类的路径)
- name:用法和id一样但是它可以添加特殊字符,一般不用
-
基于xml方式注入属性
DI:依赖注入,就是属性. DI是IOC的一种具体实现,它表示依赖注入就是注入属性
第一种注入方式:使用set方法注入 创建类,定义属性和对应的set方法
public class User{private Integer age;private String name;public void setAge(Integer age){this.age = age;}public void setName(String name){this.name = name;}}
在sprig配置文件配置对象创建配置属性注入
<!--配置User对象创建--><bean id="user" class="com.ranin.User"><!--set方法注入属性 使用property完成属性注入name:类里面属性的名称value:向属性注入的值--><property name="age" value="18"/></bean>
第二种注入方式:使用有参构造注入
创建类,定义属性,创建属性对应有参构造
public class User{//属性private String name;private Integer age;//有参构造public User(String name,Integer age){this.name;this.age;}}<!--配置order对象创建--><bean id="order" class="com.ranin.Order"><!--有参数构造注入属性--><constructor-arg name="age" value="18"/></bean>
p名称空间注入
使用P名称空间注入,可以简化基于xml配置方式 ```xml 第一步添加命名空间在配置文件中 xmlns:p=”http://www.springframework.org/schema/p“ 第二步进行属性注入,在bean标签内 类中要有set方法
<a name="d0Z0E"></a>#### IOC操作Bean管理(xml注入其他类型属性)字面量(例如int i = 5;赋上值)- null值```xml<bean id="book" class="com.ranin.Book"><!--设置一个空值--><property name="age"><null></null></property></bean>
属性值包含特殊符号
<!--属性设置特殊字符1.把<>进行转义<>2.把特殊符号的内容写到CDATA中--><bean id="book" class="com.ranin.Book"><property name="name"><value><![CDATA[<<南京>>]]></value></property></bean>
注入属性—外部bean
创建两个类service类和dao类
- 在service调用dao的方法
- 在spring配置文件中进行配置
注入属性-内部bean和级联赋值<!--service和dao对象创建--><bean id="userService" class="com.ranin.sevice.UserSevice"><!--注入userDao对象name属性值:类里面的属性名称ref属性:创建userDao对象bean标签id值--><property name="userDao" ref="userDao"></property></bean><bean id="userDao" class="com.ranin.dao.impl.UserDaoImpl"></bean>
1.对多的关系:例如部门和员工
2.在实体类之间表示一对多关系,员工表示所属部门,是用对象类型属性进行表示
3.在spring配置文件中进行配置
注入属性-级联赋值<!--内部bean--><bean id="emp" class="com.ranin.bean.Emp"><!--先设置两个普通的属性--><property name="ename" value="lucy"/><property name="gender" value="女"/><!--设置对象类型属性--><property name="dept"><bean id="dept" class="com.ranin.bean.Dept"><property name="dname" value="kaifa"/></bean></property></bean>
第一种写法
第二种写法 ```xml<!--级联赋值--><bean id="emp" class="com.ranin.bean.Emp"><!--设置两个普通属性--><property name="ename" value="lucy"/><property name="gender" value="女"/><!--级联赋值--><property name="dept" ref="dept"/></bean><bean id="dept" class="com.ranin.bean.Dept"><property name="dname" value="财务"/></bean>
<a name="jCHmc"></a>#### IOC操作Bean管理(Xml注入集合属性)注入数组类型属性<br />注入List集合类型属性<br />注入Map集合类型属性```javapublic class Stu {//数组类型属性private String[] courses;//list集合属性private List<String> list;//mapprivate Map<String,String> map;//set集合类型属性private Set<String> sets;public void setSets(Set<String> sets) {this.sets = sets;}public void setList(List<String> list) {this.list = list;}public void setMap(Map<String, String> map) {this.map = map;}public void setCourses(String[] courses) {this.courses = courses;}}
xml中
<!--集合类型的属性注入--><bean id="stu" class="com.ranin.collectiontype.Stu"><!--数组类型注入--><property name="courses"><array><value>"java"</value><value>"python"</value></array></property><!--list类型属性注入--><property name="list"><list><value>"list1"</value><value>"list2"</value></list></property><!--map--><property name="map"><map><entry key="java" value="222"/><entry key="python" value="333"/></map></property><!--set--><property name="sets"><set><value>"set1"</value><value>"set2"</value></set></property></bean>
在集合里面设置对象类型值
<!--注入list集合类型,值时对象--><property name="courseList"><list><ref bean="course1"/><ref bean="course2"/></list></property></bean><!--创建多个course对象--><bean id="course1" class="com.ranin.collectiontype.Course"><property name="cname" value="spring5"/></bean><bean id="course2" class="com.ranin.collectiontype.Course"><property name="cname" value="course2"/></bean>
把集合注入部分提取出来
在spring配置文件中引入名称空间util
xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsd">
使用util标签完成list集合注入提取
<!--提取list集合类型属性注入--><util:list id="bookList"><value>"book1"</value><value>"book2"</value><value>"book3"</value></util:list><!--提取list集合类型属性注入使用--><bean id="book" class="com.ranin.collectiontype.Book"><property name="list" ref="bookList"/></bean>
IOC操作Bean管理(FactoryBean)
1.Spring有两种类型bean,一种普通bean另外一种工厂bean(FactoryBean)
2.普通bean:在配置文件中定义bean类型就是返回类型
3.工厂bean:在配置文件定义bean类型可以和返回类型不一样
第一步创建类,让这个类作为工厂bean,实现接口FactoryBean
public class MyBean implements FactoryBean<Course> {public boolean isSingleton() {return false;}//定义返回beanpublic Course getObject() throws Exception {Course course = new Course();course.setCname("abc");return course;}public Class<?> getObjectType() {return null;}}jagva
<bean id="myBean" class="com.ranin.factoryBean.MyBean"></bean>
第二步实现接口里面的方法,在实现的方法中定义返回的bean类型
@Testpublic void test3(){ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");Course myBean = context.getBean("myBean", Course.class);System.out.println(myBean);}
Ioc操作Bean管理(bean作用域)
1.在spring里面,设置创建bean实例是单实例还是多实例
2.在spring里面,默认情况下,bean是单实例对象
@Testpublic void test2(){ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");Book book = context.getBean("book",Book.class);Book book1 = context.getBean("book",Book.class);System.out.println(book);System.out.println(book1);//结果打印出来的地址都是同一个}
3.如何设置单实例还是多实例
- 1.在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
- scope属性值
- 第一个值 默认值 singleton 表示单实例对象
第二个值prototype表示是多实例对象
<bean id="book" class="com.atguigu.spring5.collectiontype.Book" scope="prototype"><property name="list" ref="bookList"/></bean>
singleton和prototype区别
- 第一singleton表示单实例,prototype多实例
第二设置scope的值是singleton时候,加载spring配置文件时候就会创建单实例对象
从对象的创建到对象销毁的过程
2.bean的生命周期
- 通过构造器创建bean实例(无参数构造)
- 为bean的属性设置值和对其他bean的引用(调用set方法)
- 调用bean的初始化方法(需要进行配置初始化的方法)
- bean可以使用了(对象获取到了)
- 当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)
3.加上bean的后置处理器,bean声明周期有七步
- 通过构造器创建bean实例(无参数构造)
- 为bean的属性设置值和对其他bean的引用(调用set方法)
- 把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
- 调用bean的初始化方法(需要进行配置初始化的方法)
- 把bean实例传递bean后置处理器的方法postProcessAfterInitialization
- bean可以使用(对象获取到)
- 当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)
演示添加后置处理器效果
1.创建类,实现接口BeanPostProcessor,创建后置处理器
public class MyBeanPost implements BeanPostProcessor {public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化之前执行的方法");return bean;}public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化执行之后的方法");return bean;}}
xml中
<!--配置后置处理器--><bean id="myBeanPost" class="com.ranin.bean.MyBeanPost"></bean>在同一个xml中的所有bean都会执行这个配置后置处理器
IOC操作Bean管理(xml自动装配)
1.什么是自动装配
- 根据指定装配规则(属性名称或者属性类型),Spring会自动将匹配的属性值进行注入
2.演示自动装配
- 根据属性的名称自动注入
```xmlpublic void test4(){ApplicationContext context = new ClassPathXmlApplicationContext("bean5.xml");Emp emp = context.getBean("emp",Emp.class);System.out.println(emp);}
- 根据属性类型进行自动注入
测试代码都相同<br />但是要注意根据属性自动注入的话一个xml中同一个属性只能有一个bean不能有多个不然编译器无法xml
<a name="VT2ak"></a>#### IOC操作Bean管理(引入外部的属性文件)1.直接配置数据库的信息- 配置德鲁伊连接池- 引入德鲁伊连接池的jar包```xml<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version></dependency>
<!--直接配置连接池--><!--DruidDataSource dataSource = new DruidDataSource--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://47.93.182.140:3306/qingcheng_goods?serverTimezone=GMT%2B8&useSSL=false"></property><property name="username" value="root"></property><property name="password" value="123456"></property></bean>
2.引入外部的属性文件配置数据库连接板池
创建一个外部属性文件,properties格式文件,写数据库信息
prop.driverClass=com.mysql.cj.jdbc.Driverprop.url=jdbc:mysql://47.93.182.140:3306/qingcheng_goods?serverTimezone=GMT%2B8&useSSL=falseprop.username=rootprop.password=123456
把外部properties属性文件引入到spring配置文件中
- 引入context名称空间 ```xml xmlns:context=”http://www.springframework.org/schema/context“
http://www.springframework.org/schema/context/spring-context.xsd
- 在spring中的配置文件中使用标签引入外部属性文件```xml<!--引入外部的属性文件--><context:property-placeholder location="jdbc.properties"/><!--配置连接池--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${prop.driverClass}"></property><property name="url" value="${prop.url}"></property><property name="username" value="${prop.username}"></property><property name="password" value="${prop.password}"></property></bean>
基于注解方式实现
1.什么是注解
- 注解是代码特殊标记,格式为:@注解名称(属性名称=属性值,属性名称=属性值)
- 使用注解,注解可以作用在类,方法,属性上面
- 使用注解的目的:简化xml配置
2.Spring针对Bean管理中创建对象提供注解
- @Component
- @Service
- @Controller
- @Repository
上面四个注解功能是一样的,都可以用来创建bean实例
3.基于注解方式实现对象创建
第一步引入依赖
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>5.2.8.RELEASE</version></dependency>
第二步开启组件扫描spring配置文件中头部添加
第二步开启组件扫描spring配置文件中头部添加xmlns:context="http://www.springframework.org/schema/context"http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd
<!--开启组件扫描1.如果要扫描多个包,多个包之间用逗号隔开2.扫描包上层目录--><context:component-scan base-package="com.ranin"></context:component-scan>
第三步创建类,在类上添加创建对象注解
//在注解里面value属性值可以省略不写//默认值是类名称,首字母小写//UserService --userService@Component(value = "userService") //<bean id="" class=""/>写法类似public class UserService {public void add(){System.out.println("service add......");}}
4.开启组件扫描细节配置
<!--示例1use-default-filters="false"表示现在不适用默认的filter而是使用自己配置的filter,即不扫描默认规则自己配置规则context:include-filter type="annotation" 设置扫描那些内容expression="org.springframework.stereotype.Controller" 只扫描包里的controller注解--><context:component-scan base-package="com.ranin" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan><!--示例2下面配置扫描包里的所有配置context:exclude-filter 设置那些不内容不进行扫描expression="org.springframework.stereotype.Controller 不扫描controller--><context:component-scan base-package="com.ranin"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>
5.基于注解方式实现属性的注入
- @Autowired:根据属性类型进行自动装配
- 第一步把service和dao对象创建,在service和dao类添加创建对象
- 第二步在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解
- @Qualifier:根据属性的名称进行注入,和@Autowired一起使用
- @Resource:可以根据类型注入,可以根据名称注入
- @Value:注入普通类型属性
6.完全注解开发@Value(value="abc")private String name;
1.创建配置类,替代xml配置文件 ```java @Configuration//将当前类作为配置类,替代xml配置文件 @ComponentScan(basePackages = {“com.ranin”}) public class SpringConfig {
}
2.编写测试类```java@Testpublic void testService2(){//加载配置类ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);UserService userService = context.getBean("userService",UserService.class);System.out.println(userService);userService.add();}



