原理
什么是IOC(控制反转)
1、就是把对象的创建和对象之间的调用过程,交给Spring管理
2、使用目的:为了降低耦合度
IOC底层原理
a、xml解析、反射
b、工厂模式
通过工厂模式来降低耦合度
IOC(接口)
1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2、Spring提供IOC容器实现两种方式:(两个接口)
(1)BeanFactory:IOC容器基本实现,是Spring内部的使用接口。
*加载配置文件时不会创建对象,获取(使用)对象时才去创建对象。
(2)ApplicationContext: BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用。
*加载配置文件时就会把配置文件对象进行创建
ApplicationContext接口的实现类
FileSystem…:需要绝对路径(带盘符)
ClassPath…:src下路径
具体操作
IOC操作Bean管理
1、什么是Bean管理
a、Spring创建对象
b、Spring注入属性
2、Bean管理操作两种方式
1、基于xml配置文件方式实现
2、基于注解方式实现
基于xml配置文件方式实现
a、**基于xml方式创建对象**
(1)在spring配置文件中,使用bean标签,标签中添加对应属性,就可以实现对象的创建
<bean id="user" class="com.company.User"></bean>
(2) 常用属性:
*id属性 :唯一标识
*class属性:类全路径(包类路径)
*name属性(一般不用):id属性中不能加特殊符号,name可以
(3)创建对象时,默认执行无参构造方法
b、**基于xml方式注入属性**
(1)依赖注入,即注入属性
**第一种注入方式:即set方式注入**
第一步:
package com.company;
public class Book {
//定义属性
private String bName;
private String bauthor;
//创建属性对应的set方法
public void setbName(String bName) {
this.bName = bName;
}
}
第二步
<!-- set方法注入属性-->
<bean id="book" class="com.company.Book">
<!-- 使用property完成属性注入
name:类里边属性名称
value:向属性注入的值-->
<property name="bName" value="百科全书"></property>
<property name="bauthor" value="常子东"></property>
</bean>
**第二种注入方式:有参方式注入**
第一步:
package com.company;
public class Orders {
private String oName;
private String address;
//有参构造
public Orders(String oName, String address) {
this.oName = oName;
this.address = address;
}
}
第二步:
<!-- 有参构造注入属性-->
<bean id="orders" class="com.company.Orders">
<constructor-arg name="oName" value="主机"></constructor-arg>
<constructor-arg name="address" value="城"></constructor-arg>
</bean>
c、p名称空间注入(了解)
(1)
xml注入其他类型属性
1、null
<property name="address">
<null></null>
</property>
2、特殊符号(值:<<南京>>)
<property name="bauthor">
<value>
<![CDATA[<<南京>>]]>
</value>
</property>
注入属性
外部bean
(1)创建两个类:service类和dao类
(2)在service调用dao里面的方法
(3)Spring配置文件中进行配置
<bean id="userService" class="com.company.service.UserService">
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.company.dao.UserDaoImpl"></bean>
内部bean
一对多关系:部门与员工
package com.company.bean;
//员工类
public class Emp {
private String eName;
private String gender;
// 员工属于某一部门,用对象形式表示
private Dept dept;
public void seteName(String eName) {
this.eName = eName;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public void add(){
System.out.println(eName+":"+gender+":"+dept);
}
}
<bean id="emp" class="com.company.bean.Emp">
<property name="eName" value="chang"></property>
<property name="gender" value="男"></property>
<property name="dept">
<bean id="dept" class="com.company.bean.Dept">
<property name="dName" value="保卫处"></property>
</bean>
</property>
</bean>
级联赋值
<!-- 级联赋值-->
<bean id="emp" class="com.company.bean.Emp">
<property name="eName" value="chang"></property>
<property name="gender" value="男"></property>
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.company.bean.Dept">
<property name="dName" value="财务部"></property>
</bean>
xml注入集合属性
1、注入数组类型属性
2、注入List集合类型属性
3、注入Map集合类型属性
(1)创建类,定义数组、list等类型属性,生成对应的set方法
(2)在Spring配置文件中进行配置
package com.spring.collection;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Stu {
//定义数组类型属性
private String[] courses;
//List类型
private List<String> list;
//Map类型
private Map<String , String> maps;
//set集合类型
private Set<String> 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;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
public void test(){
System.out.println(Arrays.toString(courses));
System.out.println(list);
System.out.println(maps);
System.out.println(sets);
}
}
<bean id="stu" class="com.spring.collection.Stu">
<!-- 数组类型-->
<property name="courses">
<array>
<value>java课程</value>
<value>DB课程</value>
</array>
</property>
<!-- List类型-->
<property name="list">
<list>
<value>张三</value>
<value>小张</value>
</list>
</property>
<!-- List类型-->
<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>
在集合中设置对象类型值
<bean id="stu" class="com.spring.collection.Stu">
<!-- 注入list集合类型,值为对象-->
<property name="courseList">
<list>
<ref bean="course1" ></ref>
<ref bean="course2" ></ref>
</list>
</property>
</bean>
<bean id="course1" class="com.spring.collection.Course">
<property name="cName" value="Spring框架"></property>
</bean>
<bean id="course2" class="com.spring.collection.Course">
<property name="cName" value="MyBatis框架"></property>
</bean>
提取集合注入
(1)在Spring配置文件中引入名称空间util
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-beans.xsd">
</beans>
(2)使用util标签完成list集合注入提取
<!-- 提取list集合类型属性注入-->
<util:list id = "book.list">
<value>易筋经</value>
<value>九阴真经</value>
<value>九阳神功</value>
</util:list>
<!-- 提取list集合类型属性注入 使用-->
<bean id="book" class="com.spring.collection.Book">
<property name="list" ref="book.list">
</property>
</bean>
IOC操作Bean管理
spring有两种类型的bean:一种是普通bean,另一种是工厂bean(FactoryBean)
(1)普通bean:上面例子(在配置文件中定义什么类型,返回什么类型)
(2)FactoryBean:(在配置文件中定义bean类型可以和返回类型不一样)
工厂Bean:
(1)创建类,让这个类作为工厂bean(实现接口FactoryBean)
(2)实现接口中的方法,在实现的方法中定义返回的bean类型
public class MyBean implements FactoryBean<Course> {
// 定义返回的bean对象类型
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setcName("abc");
return course;
}
}
IOC操作Bean管理(bean作用域:单实例还是多实例,默认单实例)
//默认单实例
@Test
public void testCollection02(){
ApplicationContext context =
new ClassPathXmlApplicationContext("appliction2.xml");
Book book1 = context.getBean("book", Book.class);
Book book2 = context.getBean("book", Book.class);
// book.test();
System.out.println(book1);
System.out.println(book2);
System.out.println(book1.equals(book2));
}
(1)在Spring配置文件中bean标签中有属性(scope)用于设置单还是多实例
(2)scope属性值
1、singleton:表示单实例对象(默认)
设置为此值时,加载spring配置文件时就回创建单实例对象
2、prototype,表示多实例对象
设置为此值时,调用getBean方法时创建多实例对象
<bean id="book" class="com.spring.collection.Book" scope="prototype">
</bean>
3、request:创建对象放到request中(不常用)
4、session:创建对象放到session中(不常用)
bean生命周期(面试重点):从对象创建到对象销毁的过程
a、通过构造器创建bean实例(无参构造)
b、为bean的属性设置值和队其他bean引用(set方法)
把bean实例传递给bean后置处理器的方法(postProcessBeforeInitialization方法)
c、调用bean的初始化方法(要进行配置)
把bean实例传递给bean后置处理器的方法(postProcessAfterInitialization方法)
d、bean可以使用(获取到对象)
e、容器关闭,调用bean的销毁方法(需要进行配置销毁方法)
<bean id="orders" class="com.spring.bean.Orders" init-method="initMethod" destroy-method="destoryMethod">
<property name="oName" value="手机"></property>
</bean>
<!-- 配置后置处理器,配置后为所有bean添加后置处理器-->
<bean id="myBeanPost" class="com.spring.bean.MyBeanPost"></bean>
package com.spring.bean;
public class Orders {
//无参数构造
public Orders() {
System.out.println("第一步 执行无参数构造创建bean实例");
}
public String oName;
public void setoName(String nName) {
this.oName = nName;
System.out.println("第二步 调用set方法设置属性值");
}
//创建执行的初始化方法
public void initMethod(){
//配置文件中的 <bean id="orders" class="com.spring.bean.Orders" init-method="initMethod">
System.out.println("第三步 执行初始化方法");
}
public void destoryMethod(){
System.out.println("第五步 执行销毁的方法");
}
}
//后置处理器类
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行的方法");
return null;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行的方法");
return null;
}
}
@Test
public void testCollection04(){
ApplicationContext context =
new ClassPathXmlApplicationContext("appliction4.xml");
// ClassPathXmlApplicationContext context =
// new ClassPathXmlApplicationContext("appliction4.xml");
Orders orders = context.getBean("orders",Orders.class);
System.out.println("第四步,获取创建bean实例对象");
System.out.println(orders);
// 手动销毁bean实例
((ClassPathXmlApplicationContext) context).close();
}
XML方式的自动装配(一般使用注解实现自动装配)
自动装配:根据指定的装配规则,Spring自动将匹配的属性值进行注入(上面全部是手动装配)
两种方式:根据属性名称、根据属性类型
<!-- 自动装配
bean标签属性autowire,配置自动装配
autowire有两个值:
byName根据属性名称注入 :注入bean的id值和类属性名称一样
byType根据属性类型注入 :
-->
<bean id="emp" class="com.spring.autowire.Emp" autowire="byType"></bean>
<bean id="dept" class="com.spring.autowire.Dept"></bean>
XML方式引入外部属性文件
(1)直接配置数据库信息
配置德鲁伊连接池
引入德鲁伊jar包
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysql:///localhost:3306/userDb" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
(2)通过外部属性文件配置数据库连接池
创建外部属性文件,properties格式文件,写数据库信息
prop.driverClass = com.mysql.jdbc.Driver
prop.url = jdbc:mysql:///localhost:3306/userDb
prop.userName = root
prop.password = 123456
把外部properties属性文件引入spring配置文件中
a、引入context命名空间
b、spring配置文件中使用标签引入
<?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"
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/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${prop.url}" />
<property name="username" value="${prop.userName}" />
<property name="password" value="${prop.password}" />
<property name="driverClassName" value="${prop.driverClass}" />
</bean>
</beans>
基于注解方式实现
1、什么是注解:
(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值…)
(2)使用注解,可以作用在类上、方法上、属性上
(3)使用注解的目的:简化XML配置
2、Spring针对Bean管理中创建对象提供的注解
@Component @Service @Controller @Repository
四个注解功能相同,都可以用来创建对象
第一步 引入依赖
第二步 开启组件扫描
<?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"
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/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启组件扫描
1、扫描多个包,多个包之间用逗号隔开
2、扫描包的上层目录
-->
<!-- 写法1-->
<context:component-scan base-package="com.spring.dao,com.spring.Service"></context:component-scan>
<!--写法2-->
<context:component-scan base-package="com.spring"></context:component-scan>
<!-- 手动配置过滤器
use-default-filters="false"表示不使用现在默认的filter,自己配置filter
context:include-filter 设置扫描哪些内容
-->
<context:component-scan base-package="com.spring" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!--只扫描带Controller注解的-->
</context:component-scan>
<!-- 扫描包中的全部内容-->
<!-- context:exclude-filter 设置哪些内容不进行扫描-->
<context:component-scan base-package="com.spring" use-default-filters="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!--不扫描带Controller注解的-->
</context:component-scan>
</beans>
第三步 创建类,在类上面添加创建对象注解
package com.spring.Service;
import org.springframework.stereotype.Component;
//加上注解就不需要在配置文件中配置
//注解后的value值可以省略 默认值是类名称,首字母小写
@Component
public class UserService {
public void add(){
System.out.println("Service add.....");
}
}
基于注解方式属性注入
@AutoWired :根据属性类型进行自动装配
//第一步创建service和dao对象,在service和dao类添加创建对象注解
//第二步在service注入dao对象,在属性上使用注解
@Service
public class UserService {
/*
* 定义dao类型属性
* 不需要添加set方法
* 添加注入属性注解*/
@Autowired
private UserDao userDao;
public void add(){
System.out.println("Service add.....");
userDao.add();
}
}
@Qualifier :根据属性名称进行注入
@Repository(value = "userDaoImpl11")
public class UserDaoImpl implements UserDao{
//这个注解要和@AutoWired一起使用
@Service
public class UserService {
/*
* 定义dao类型属性
* 不需要添加set方法
* 添加注入属性注解*/
@Autowired
//一个借口有多个实现类,指定实现类的名称注入
@Qualifier(value = "userDaoImpl11")
private UserDao userDao;
public void add(){
System.out.println("Service add.....");
userDao.add();
}
}
@Resource (不是spring提供 不推荐):可以根据类型注入,也可以根据名称注入
@Service
public class UserService{
@Resource //根据类型进行注入
// @Resource(name = "userDaoImpl11") //根据名称进行注入
private UserDao userDao;
public void add(){
System.out.println("Service add.....");
userDao.add();
}
}
@Value :注入普通类型属性
@Service
public class UserService{
@Value(value = "abc")
private String name;
public void add(){
System.out.println("Service add.....");
System.out.println(name);
}
}
完全注解开发(没有xml文件)
(1)创建配置类
package com.spring.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration //作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.spring"})
public class SpringConfig {
}
@Test
public void test02(){
//主要是这一行变了
ApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
这种方法的优缺点参考
添加链接描述