基本概念
- Spring是轻量级、开源的Java EE框架
- Spring有两个核心部分:IOC和AOP
(1)IOC:inversion of control,控制反转,把创建对象过程交给Spring进行管理
(2)AOP:aspect of plane,面向切面,不修改源码进行功能增强 - 下载Spring地址:https://repo.spring.io/release/org/springframework/spring/
在IDEA中导入Spring的依赖jar包
- 新建一个Spring的工程
- 在工程下新建一个文件夹,命名为lib
- 将5个基本包复制粘贴到此文件夹下
- 5个基本包下载链接:https://wwa.lanzous.com/imbUkon54ub
- File-project structure
-导入lib文件夹下的jar包
- 在src下新建package-新建class
public class User {
public void say(){
System.out.println("hello world");
}
}
创建Spring配置文件,在配置文件配置创建的对象
- Spring的配置文件格式为XML
- src下创建Spring的配置文件,命名为bean1.xml
- 填写配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!--配置User对象的创建-->
<bean id="user" class="com.spring5.User"></bean>
</beans>
- 编写测试案例
public class TestSpring5 {
@Test
public void testAdd(){
//1. 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//2. 获取配置创建的对象
User user = context.getBean("user", User.class);
System.out.println(user);
user.say();
}
IOC容器
概念和原理
- 什么是IOC?
(1)控制反转,把对象创建和对象之间的调用过程,交给Spring管理
(2)使用IOC目的:为了降低耦合度
(3)上面的测试案例就是IOC的实现 - IOC底层原理
(1)XML解析、工厂设计模式、反射 - IOC过程
(1)xml配置文件,配置创建的对象
<bean id="dao" class="com.UserDap"></bean>
(2)有service类和dao类,创建工厂类
class UserFactory{
public static UserDao getDao(){
String classValue = class属性值;//xml解析
Class clazz = Class.forName(classsValue);//通过反射创建对象
return (UserDao)clazz.newInstance();
}
}
IOC接口
(1)IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
(2)Spring提供IOC容器实现两种方式:两个接口
- BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员使用.加载配置文件时不会创建对象,在获取对象(使用)才去创建对象
- ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用。加载配置文件时候就会把在配置文件对象进行创建
- 在实际开发时,一般会使用第二种接口,因为把耗时耗资源的过程放在服务器启动时比较合适。
ApplicationContext的主要实现类
(1)FileSystemApplicationContext:磁盘路径
(2)ClassPathApplicationContex:包+类名
IOC操作和Bean管理
Bean管理
- 两个操作:Spring创建对象,Spring注入属性
- 两种方式:基于xml配置文件方式;基于注解方式
基于xml配置文件
- 使用bean标签,标签里添加对应的属性,就可以实现对象创建
- 常用属性:
- id:类在xml配置文件中的唯一标识
- class:类全路径(包类路径)
- 创建对象时默认执行无参构造器,如果类没有无参构造器(被含参构造器覆盖)会报错,无法创建对象。因此,在创建类时,最好显式将无参构造器加上
注入属性
使用set方法注入属性(值)
- 在类中要有set方法实现对类属性的修改
public class User {
private String name;
private int age;
public User() {
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void say(){
System.out.println("hello world");
}
}
- 在xml配置文件中的bean标签中添加property标签:
<!--配置User对象的创建-->
<bean id="user" class="com.spring5.User">
<!--set方法属性注入
property标签
name:类属性名;
value:要注入的类属性值
-->
<property name="name" value = "cat"></property>
<property name="age" value = "24"></property>
</bean>
- 外部bean注入属性——属性类型为引用类型
【外部bean】:指在一个bean标签中引用另一个bean标签
- 类中含有属性类型为另一个类
//Animal接口
public interface Animal {
public void eat();
}
//Tiger实现类
public class Tiger implements Animal{
public Tiger() {
}
@Override
public void eat() {
System.out.println("老虎食野猪");
}
}
//主类
public Animal animal;
public void setAnimal(Animal animal) {
this.animal = animal;
}
- 编写xml配置文件
<bean id="user" class="com.spring5.User">
<property name="animal" ref="animal"></property>
</bean>
<bean id="animal" class="com.spring5.userServer.Tiger">
</bean>
- 内部bean注入属性——属性类型为引用类型
- 被应用的类:Department类
public class Department {
private String departName;
public Department() {
}
public void setDepartName(String departName) {
this.departName = departName;
}
@Override
public String toString() {
return "Department{" +
"departName='" + departName + '\'' +
'}';
}
}
- 主类:Employee类
public class Employee {
private int empId;
private String empName;
private Department departmentName;
public Employee() {
}
public void setEmpId(int empId) {
this.empId = empId;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public void setDepartmentName(Department departmentName) {
this.departmentName = departmentName;
}
@Override
public String toString() {
return "Employee{" +
"empId=" + empId +
", empName='" + empName + '\'' +
", departmentName=" + departmentName +
'}';
}
}
- xml配置文件
<!--内部bean注入属性-->
<bean id="employee" class="com.spring5.userServer.Employee">
<property name="empId" value="1001"></property>
<property name="empName" value="小明"></property>
<property name="departmentName">
<bean id="department" class="com.spring5.userServer.Department">
<property name="departName" value="人力资源部"></property>
</bean>
</property>
</bean>
- 测试方法
@Test
public void testBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Employee e1 = context.getBean("employee", Employee.class);
System.out.println(e1);
}
- 输入类型为集合的属性值
- 学生类
public class Student {
private double[] grades;
private List<String> subjects;
private Set<String> pets;
private Map<String,Double> body;
public Student() {
}
public void setGrades(double[] grades) {
this.grades = grades;
}
public void setSubjects(List<String> subjects) {
this.subjects = subjects;
}
public void setPets(Set<String> pets) {
this.pets = pets;
}
public void setBody(Map<String, Double> body) {
this.body = body;
}
@Override
public String toString() {
return "Student{" +
"grades=" + Arrays.toString(grades) +
", subjects=" + subjects +
", pets=" + pets +
", body=" + body +
'}';
}
}
- xml配置文件
<!--集合类属性的注入-->
<bean id="stu" class="com.spring5.collection.Student">
<property name="grades">
<array>
<value>89</value>
<value>97</value>
<value>100</value>
</array>
</property>
<property name="subjects">
<list>
<value>语文</value>
<value>数学</value>
<value>英语</value>
</list>
</property>
<property name="pets">
<set>
<value>猫</value>
<value>狗</value>
<value>鸟</value>
</set>
</property>
<property name="body">
<map>
<entry key="身高" value="173"></entry>
<entry key="体重" value="60"></entry>
<entry key="颜值" value="100"></entry>
</map>
</property>
</bean>
- 测试方法
@Test
public void testCollection(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Student stu = context.getBean("stu", Student.class);
System.out.println(stu);
}
- 当集合中的值为对象时
Book类
public class Book {
private String bookName;
public Book() {
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
@Override
public String toString() {
return "Book{" +
"bookName='" + bookName + '\'' +
'}';
}
}
Student类新增
private List<Book> bookList;
public void setBookList(List<Book> bookList) {
this.bookList = bookList;
}
public void printBook(){
System.out.println(bookList);
}
xml配置文件新增
...
<property name="bookList">
<list>
<ref bean="book1"></ref>
<ref bean="book2"></ref>
</list>
</property>
<bean id="book1" class="com.spring5.collection.Book">
<property name="bookName" value="JAVA编程思想"></property>
...
</bean>
<bean id="book2" class="com.spring5.collection.Book">
<property name="bookName" value="程序员面试指南"></property>
</bean>
- 把集合注入部分提取出来
- Teacher类
public class Teacher {
private List<String> tlist;
public Teacher() {
}
public void setTlist(List<String> tlist) {
this.tlist = tlist;
}
@Override
public String toString() {
return "Teacher{" +
"tlist=" + tlist +
'}';
}
}
- 在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:p="http://www.springframework.org/schema/p"
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-util.xsd">
- 使用util标签完成list集合注入提取
<!--提取list集合类型属性的注入-->
<util:list id="teacherList">
<value>张老师</value>
<value>马老师</value>
<value>王老师</value>
</util:list>
<bean id="teacher" class="com.spring5.collection.Teacher">
<property name="tlist" ref="teacherList"></property>
</bean>
- 测试方法
@Test
public void testCollection2(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Teacher teacher = context.getBean("teacher", Teacher.class);
System.out.println(teacher);
}
使用含参构造器注入属性值
- 在类中添加含参构造器
public User(String name, int age) {
this.name = name;
this.age = age;
}
- 在xml配置文件中添加constructor-arg标签
<constructor-arg name="name" value="tiger"></constructor-arg>
<constructor-arg name="age" value="10"></constructor-arg>
特殊属性值的注入
- null
<property name="name">
<null/>
</property>
- 特殊符号
- < >分别表示<和>
<property name="name" value="<西安>"></property>
- 将特殊符号内容写到CDATA中
<property name="name">
<value><![CDATA[<西安>]]></value>
</property>
FactoryBean
- Spring有两种类型bean,一种普通bean,另外一种是工厂bean
- 区别
(1)普通bean:在配置文件中定义bean类型就是返回类型
(2)工厂bean:在配置文件定义bean类型可以和返回类型不一样 - 创建FactoryBean
(1)创建类,让这个类作为工厂bean,实现接口FactoryBean
(2)实现接口里的方法,在实现的方法中定义返回的bean类型
public class Phone {
private String phoneBrand;
public Phone() {
}
public void setPhoneBrand(String phoneBrand) {
this.phoneBrand = phoneBrand;
}
@Override
public String toString() {
return "Phone{" +
"phoneBrand='" + phoneBrand + '\'' +
'}';
}
}
public class PhoneFactory implements FactoryBean {
@Override
public Phone getObject() {
Phone myPhone = new Phone();
myPhone.setPhoneBrand("Apple");
return myPhone;
}
@Override
public Class<?> getObjectType() {
return null;
}
}
- xml配置文件
<bean id="phone" class="com.spring5.factorybean.Phone"></bean>
<bean id="phoneFactory" class="com.spring5.factorybean.PhoneFactory"></bean>
- 测试方法
@Test
public void testFactoryBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Phone phone = context.getBean("phoneFactory", Phone.class);
System.out.println(phone);
}
bean的作用域和生命周期
bean的作用域
- 在Spring中,设置创建bean实例是单实例还是多实例
- 默认情况下,一个bean标签表示一个单实例对象
- scope属性值
(1)singleton:表示单实例对象
(2)prototype:表示多实例对象
<bean id="phoneFactory" class="com.spring5.factorybean.PhoneFactory" scope="prototype"></bean>
(3)设置为scope是singleton时,加载spring配置文件时就会创建单实例对象;而scope为prototype时,对象在调用getBean()方法时才创建多实例对象。
bean的生命周期
- 通过构造器创建bean实例(无参构造器)
- 为bean的属性设置值和对其他bean引用(调用set方法)
- 调用bean的初始化方法(需要配置初始化的方法)
- bean可以使用了(对象获取到了)
- 当容器关闭时候,调用bean的销毁方法(需要进行配置销毁的方法)
- 演示bean生命周期
- BeanLife类
public class BeanLife {
private String name;
public BeanLife() {
System.out.println("1. 无参构造器创建bean实例对象");
}
public void setName(String name) {
this.name = name;
System.out.println("2. 调用set方法设置属性值");
}
public void initMethod(){
System.out.println("3. 调用初始化方法");
}
public void destroyMethod(){
System.out.println("5. 调用销毁对象的方法");
}
@Override
public String toString() {
return "BeanLife{" +
"name='" + name + '\'' +
'}';
}
}
- xml配置文件
<bean id="beanlife" class="com.spring5.beanlife.BeanLife" init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="bean的生命周期"></property>
</bean>
- 测试方法
@Test
public void testBeanLife(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
BeanLife beanlife = context.getBean("beanlife", BeanLife.class);
System.out.println("4. 获取创建的bean实例对象");
System.out.println(beanlife);
//手动让bean实例销毁
((ClassPathXmlApplicationContext) context).close();
}
- 测试结果
- 补充:
在第三步前后各有一步
(1) 把bean实例传递bean后置处理器的方法postProcessBeforeInitialization
(2) 把bean实例传递bean后置处理器方法postProcessAfterInitialization
xml自动装配
- autowire标签
- byName属性和byType属性
- 实际开发很少用
外部属性文件
- 直接配置数据库信息
(1)配置德鲁伊连接池
(2)引入德鲁伊连接池依赖jar包:下载地址:https://wwa.lanzous.com/i5Nsiooc2eb
引入方法见上面导入spring的基本jar包方法
(3)编写xml配置文件
<!---直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.musql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/usserDb"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
- 引入外部属性文件配置数据库连接池
(1)创建外部属性文件,properties格式文件,写入数据库的连接信息
src-new-file
命名为jdbc.properties
文件内容:
prop.driver=com.musql.jdbc.Driver
prop.url=dbc:mysql://localhost:3306/usserDb
prop.userName=root
pprop.password=root
(2)把外部properties属性文件引入到spring的xml配置文件中
- 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 http://www.springframework.org/schema/beans/spring-beans.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="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>