概念和原理
什么是IOC
控制反转,把对象的创建和对象之间的调用过程,交给Spring进行管理使用IOC目的:为了耦合度降低做入门的案例就是IOC实现工厂模式
目的:降低耦合度到最低限度
IOC过程,进一步降低耦合度
xml配置文件,配置创建的对象
<bean id="dao" class="com.yang.UserDao"/>第二步 有service和dao类,创建工厂类
class UserFactory{ public static UserDao getDao{ String classValue = class属性值;//1.xml解析得到 //2.通过反射得到对象 Class clazz = Class.forName(classValue); return (UserDao)clazz.newInstance(); } }什么是Bean管理?包括创建对象与注入属性
Spring创建对象Spring注入属性DI:依赖注入,就是注入属性,DI是IOC的一种实现方式
实体类创建
package com.yang; public class Book { private String bname; private String author; //set方法注入 public void setBname(String bname, String author) { this.bname = bname; this.author = author; } public Book() { } public void setBname(String bname) { this.bname = bname; } public void setAuthor(String author) { this.author = author; } //有参构造注入 public Book(String bname) { this.bname = bname; } }bean文件配置
<!-- set方法注入属性--> <bean id="book" class="com.yang.Book"> <!-- 使用property完成属性注入 name属性代表字段名称 value为注入的值 --> <property name="bname" value="天龙八部"/> <property name="author" value="杨剑"/> </bean>创建类,定义属性,创建构造方法
public class Orders { private String name; private String address; public Orders(String name, String address) { this.name = name; this.address = address; } }在spring配置文件中配置
<bean id="orders" class="com.yang.Orders"> <constructor-arg name="name" value="电脑"/> <constructor-arg name="address" value="中国"/> </bean>使用p名称空间注入可以简化基于xml的配置方式
在配置文件中添加p名称空间
xmlns:p="http://www.springframework.org/schema/p"进行属性注入,在bean标签里进行操作
<bean id="book" class="com.yang.Book" p:bname="名字" p:author="作者"/>字面量
空值
<property name="author"> <null/> </property>属性值包含特殊符号
转义:> <
CDATE
<property name="author"> <value> <![CDATA[ <<南京>> ]]> </value> </property>注入属性-外部bean
创建两个类service和dao类
在service调用dao里面的方法
在Spring配置文件中进行配置
<!-- service和dao对象的创建--> <bean id="userService" class="com.yang.service.UserService"> <!-- 注入userDao对象 name:属性值:类里面的属性名称 --> <property name="userDao" ref="userDaoImpl"/> </bean> <bean id="userDaoImpl" class="com.yang.dao.UserDaoImpl"/>注入属性-内部bean和级联赋值
一对多关系:部门和员工
一个部门有多个员工,一个员工属于某一个部门
在实体类中体现一对多关系
员工表示所属部门,用对象表示
//部门类 public class Department { private String dName; public void setdName(String dName) { this.dName = dName; } } //员工类 public class Emp { private String ename; private String gender; //员工属于某一个部门,使用对象形式表示 private Department department; public void setEname(String ename) { this.ename = ename; } public void setGender(String gender) { this.gender = gender; } }在spring配置文件中进行相关配置
<!--内部bean--> <bean id="emp" class="com.yang.bean.Emp"> <!-- 先设置两个普通属性--> <property name="ename" value="ya"/> <property name="gender" value="男"/> <!-- 对象类型属性--> <property name="department"> <bean class="com.yang.bean.Department"> <property name="dName" value="公司"/> </bean> </property> </bean>注入属性:级联赋值
第一种方式
<bean id="emp" class="com.yang.bean.Emp"> <!-- 先设置两个普通属性--> <property name="ename" value="ya"/> <property name="gender" value="男"/> <!-- 对象类型属性--> <!-- 级联赋值--> <property name="department" ref="deparment"/> </bean> <bean id="deparment" class="com.yang.bean.Department"> <property name="dName" value="财务部"/> </bean> 第二种方式,需要生成deparment的get方法 <bean id="emp" class="com.yang.bean.Emp"> <!-- 先设置两个普通属性--> <property name="ename" value="ya"/> <property name="gender" value="男"/> <!-- 对象类型属性--> <!-- 级联赋值--> <property name="department" ref="department"/> <property name="department.dName" value="cai"/> </bean> <bean id="department" class="com.yang.bean.Department"> <property name="dName" value="财务部"/> </bean>xml注入集合属性
注入数组类型属性注入List集合注入Map集合类型的属性创建类,定义数组, list,map,set集合属性,生成对应的set方法
在spring配置文件中配置
<bean id="student" class="com.yang.collectionType.Student"> <!-- 数组类型--> <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 key="PHP" value="php"/> </map> </property> <!-- set--> <property name="set"> <set> <value>123</value> <value>mysql</value> </set> </property> </bean>在集合里设置对象类型值
<property name="courseList"> <list> <ref bean="course1"/> <ref bean="course2"/> </list> </property> <bean id="course1" class="com.yang.collectionType.Course"> <property name="cname" value="Spring5框架"/> </bean> <bean id="course2" class="com.yang.collectionType.Course"> <property name="cname" value="MyBatis框架"/> </bean>把集合注入部分提取出来
在Spring配置文件中引入名称空间 util
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd ">使用util标签提取
<util:list id="bookList"> <value>三国</value> <value>水浒</value> </util:list> <bean id="book" class="com.yang.collectionType.Book"> <property name="list" ref="bookList"/> </bean>IOC操作Bean管理(FactoryBean)
Spring有两种类型的Bean,一种普通Bean,另一种:工厂Bean(FactoryBean)
普通Bean:在配置文件中定义的Bean类型就是你的返回类型
工厂Bean:在配置文件中定义的Bean类型可以和返回类型不一样
第一步:让这个类作为工厂Bean,实现接口FactoryBean
<bean id="myBean" class="com.yang.factorybean.MyBean"> </bean>第二步:实现接口里的方法,在实现的方法中定义返回的bean类型
public class MyBean implements FactoryBean<Course> { //定义返回Bean public Course getObject() throws Exception { Course course = new Course(); course.setCname("abc"); return course; } public Class<?> getObjectType() { return null; } public boolean isSingleton() { return false; } }IOC操作Bean管理(Bean作用域)
在Spring里面,设置创建bean实例是单实例还是多实例
在Spring里面,默认情况下,bean是单实例对象
如何设置单实例还是多实例
spring配置文件中bean标签里有属性(scope)用于设置单实例还是多实例
scope属性值
第一个值 默认值,singleton,表示单实例对象
第二个值 prototype,多实例对象
scope和prototype的区别
第一:singleton:单实例
prototype:多实例
第二:设置scope为singleton的时候,加载配置文件的时候就会创建一个单实例对象
设置scope值是prototype的时候,不是加载配置文件时创建对象,在调用getBean方法的时候去创建多实例对象
还有request,session,一般不用,了解即可
生命周期: 从对象创建到对象销毁的的过程
bean生命周期
通过构造器创建bean实例(无参构造)为bean的属性设置值和对其他bean的引用(调用set方法)调用bean的初始化的方法(需要进行配置)bean可以使用了(对象获取到了)当容器在关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)演示bean的生命周期
package com.yang.bean; public class Orders { private String oname; public void setOname(String oname) { this.oname = oname; System.out.println("第二部,调用set方法设置属性值"); } public Orders(){ System.out.println("第一步,无参构造创建bean实例"); } //创建执行的初始化方法 public void initMethod(){ System.out.println("第三步,执行初始化的方法"); } //创建销毁的方法 public void destroyMethod(){ System.out.println("第五步,执行销毁的方法"); } } public void test2(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Orders orders = context.getBean("orders", Orders.class); System.out.println("第四部,获取创建bean实例的对象"); System.out.println(orders); //手动销毁bean实例 context.close(); }bean的后置处理器,bean生命周期变为七步
bean生命周期
通过构造器创建bean实例(无参构造)为bean的属性设置值和对其他bean的引用(调用set方法)把bean实例传给bean后置处理器的方法postProcessBeforeInitialization调用bean的初始化的方法(需要进行配置)把bean实例传给bean后置处理器的方法postProcessAfterInitializationbean可以使用了(对象获取到了)当容器在关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)添加后置处理器效果
创建类,实现接口BeanPostProcessor,创建后置处理器
package com.yang.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.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; } }在bean中配置,自动为所有bean加上
<bean id="myBeanPost" class="com.yang.bean.MyBeanPost"/>xml自动装配
什么是自动装配?
根据指定装配规则(属性名称或属性类型),Spring自动将匹配的属性值进行注入
演示自动装配过程
根据属性名称进行自动注入 byName
<bean id="emp" class="com.yang.autowire.Emp" autowire="byName"> <!-- <property name="dept" ref="dept"/>--> </bean> <bean id="dept" class="com.yang.autowire.Dept"/>根据属性类型进行自动注入 byType
<bean id="emp" class="com.yang.autowire.Emp" autowire="byType"> <!-- <property name="dept" ref="dept"/>--> </bean> <bean id="dept" class="com.yang.autowire.Dept"/>外部属性文件
直接配置数据库信息,配置druid连接池
配置druid连接池
引入druid连接池依赖
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean>引入外部属性文件配置数据库连接池
创建外部属性文件,properties格式文件,写数据库信息
prop.driverClass=com.mysql.jdbc.Driver prop.url=jdbc:mysql://localhost:3306/mybatis?useSSL=true prop.userName=root prop.password=123456把外部properties属性文件引入到Spring配置文件中
引入context名称空间
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">在spring配置文件中使用标签引入外部属性文件
写入
<context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${prop.driverClass}"/> <property name="url" value="${prop.url}"/> <property name="username" value="${prop.userName}"/> <property name="password" value="${prop.password}"/> </bean>spring针对Bean管理中创建对象提供注解
@Component
@Service
@Controller
@Respository
上面的四个注解功能是一样的,都可以用来创建bean实例
基于注解方式实现对象的创建
引入AOP依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.2.9.RELEASE</version> </dependency>开启组件扫描
<!-- 开启组件扫描 1.如果扫描多个包,多个包用逗号隔开 2.扫描上层目录 --> <context:component-scan base-package="com.yang"/>创建类,在类上面添加对象注解
//在注解里的value属性值可以省略不写 //默认值是类的名称,把首字母小写 @Service(value = "userService") //<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.yang" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan> <!-- 事例2: context:exclude-filter 设置哪些内容不进行扫描 --> <context:component-scan base-package="com.yang"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>注解方式属性注入
@Autowired:根据属性类型进行自动装配@Qualifier:根据属性名称进行注入@Resource:可以根据类型注入,也可以根据名称注入@Value:注入普通类型属性@Autowired
把service和dao对象创建,在service和dao类添加创建对象的注解
在service注入dao,在service类添加dao类型的属性,在属性上面使用注解
//在注解里的value属性值可以省略不写 //默认值是类的名称,把首字母小写 @Service(value = "userService") //<bean id="userService" class=""/> public class UserService { //定义dao类型属性 //不需要添加set方法 //添加属性注解 @Autowired //根据类型进行注入 private UserDao userDao; public void add() { System.out.println("service add.............."); userDao.add(); } } @Repository public class UserDaoImpl implements UserDao{ public void add() { System.out.println("dao add...."); } }@Qualifier:根据属性名称进行注入
这个@Qualifier注解的使用要和上面的@Autowired一起使用
@Repository(value = "userDaoImpl1") public class UserDaoImpl implements UserDao{ public void add() { System.out.println("dao add...."); } } @Autowired //根据类型进行注入 @Qualifier(value = "userDaoImpl1") //根据名称及逆行注入@Resource:可以根据类型注入,也可以根据名称注入,包:javax.annotation.Resource
@Service(value = "userService") //<bean id="userService" class=""/> public class UserService { //@Resource //根据类型进行注入 @Resource(name = "userDaoImpl1")//根据名称进行注入 private UserDao userDao; public void add() { System.out.println("service add.............."); userDao.add(); } }@Value:注入普通属性
@Value(value = "yj") private String name;完全注解开发
创建配置类,替代xml配置文件
@Configuration //作为配置类 ,替代xml配置文件 @ComponentScan(basePackages = {"com.yang"}) public class SpringConfig { }测试类
@Test public void test2(){ //加载配置类 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = context.getBean("userService", UserService.class); userService.add(); }