1.Spring框架的简介。
什么是Spring框架:
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。
简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
Spring框架模型:
Spring5的下载地址:
https://repo.spring.io/release/org/springframework/spring/
可以选择已经发行的版本进行下载:
选择下载即可:
下载之后,就可以在idea中创建一个普通的Java工程,然后再导入相应的jar包就行。
Ioc基础jar包:core containers
2.Spring核心之一:IOC(Inversion of Control,即控制反转。它不是什么技术,而是一种设计思想。)
传统的创建对象的方法是直接通过 new 关键字,而 spring 则是通过 IOC 容器来创建对象,也就是说我们将创建对象的控制权交给了 IOC 容器。我们可以用一句话来概括 IOC:
IOC 让程序员不在关注怎么去创建对象,而是关注与对象创建之后的操作,把对象的创建、初始化、销毁等工作交给spring容器来做。
IOC的通俗理解:
IoC(Inversion of Control,控制反转)。这是spring的核心,贯穿始终。所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。这是什么意思呢,举个简单的例子,我们是如何找女朋友的?常见的情况是,我们到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、qq号、电话号、ip号、iq号………,想办法认识她们,投其所好送其所要,然后嘿嘿……这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传统的程序开发也是如此,在一个对象中,如果要使用另外的对象,就必须得到它(自己new一个,或者从JNDI中查询一个),使用完之后还要将对象销毁(比如Connection等),对象始终会和其他的接口或类藕合起来。
那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
在不用Spring之前:
使用IOC:
3.利用Spring来创建对象:
1.IOC的思想基于IOC容器完成,IOC容器底层就是对象工厂
2.Spring提供IOC容器实现的两种方式:(也就是两个接口)
- BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
加载配置文件的时候不会创建对象,在获取对象(使用)的时候才去创建对象
- ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般有开发人员进行使用。
加载配置文件时候就会把在配置文件中的对象进行创建。
3.ApplicationContext接口的实现类
FileSystemXmlApplicationContext:是系统路径的配置文件,也就是包含盘符的配置文件的路径
ClassPathXmlApplicationContext:是在当前src目录下的配置文件。
IOC操作bean管理
1.什么是bean管理:bean管理指的是两个操作
- Spring创建对象:
- Spring注入属性:
2.bean管理操作有两种方式:
- 基于xml配置文件方式实现
- 基于注解方式实现
4.方式一:基于xml方式进行bean管理(普通的bean)
1.基于xml方式创建对象:
在src在创建xml文件:
在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
在bean标签中有很多属性,介绍常用的属性
- id属性:唯一标识
- class属性:类全路径(包和类路径)
创建对象时候,默认也是执行无参数构造方法完成对象的创建。
<!--配置User对象-->
<bean id="user" class="com.lsy.bean.User">
</bean>
package com.lsy.bean;
/**
* @Description: User的bean对象
* @Author:lsy
* @Date:
*/
public class User {
public void add(){
System.out.println("Add---");
}
}
//测试类
/**
* UserTest
*/
@Test
public void test1(){
//1.加载Spring的配置文件
//文件路径默认在src下。
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
//2.获取配置创建的对象
User user = context.getBean("user", User.class);
System.out.println(user);
user.add();
}
2.基于xml方式注入属性(DI:依赖注入,就是注入属性)
两种方式:
- 方式一:使用set方法进行注入
package com.lsy.bean;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class Book {
private String bname;
private String bauthor;
public void setBname(String bname) {
this.bname = bname;
}
public void setBauthor(String bauthor) {
this.bauthor = bauthor;
}
public void testBook(){
System.out.println(bname+":"+bauthor);
}
}
<bean id="book" class="com.lsy.bean.Book">
<property name="bname" value="时间简史"></property>
<property name="bauthor" value="霍金"></property>
</bean>
@Test
public void test2(){
//1.加载Spring的配置文件
//文件路径默认在src下。
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
//2.获取配置创建的对象
Book book = context.getBean("book", Book.class);
System.out.println(book);
book.testBook();
}
- 方式二:使用有参数构造方法进行注入
package com.lsy.bean;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class Orders {
private String oname;
private String address;
//有参构造
public Orders(String oname, String address) {
this.oname = oname;
this.address = address;
}
public void ordertest(){
System.out.println("ordertest");
}
}
bean1.xml文件中
<bean id="orders" class="com.lsy.bean.Orders">
<constructor-arg name="oname" value="computer"></constructor-arg>
<constructor-arg name="address" value="china"></constructor-arg>
</bean>
方式三:P名称空间注入
第一步:添加p名称空间在配置文件中。
第二步:进行属性注入,在bean标签里面进行操作
<bean id="book" class="com.lsy.bean.Book" p:bname="tomcat" p:bauthor="lsy">
</bean>
xml注入其他类型的属性:空值和含有特殊符号的属性值。
<!-- 可以设置null值-->
<!-- <property name="address" >-->
<!-- <null/>-->
<!-- </property>-->
<!-- 含有特殊的字符,报错-->
<!-- <property name="address" value="<<南京>>">-->
<!-- -->
<!-- </property>-->
<!-- 可以用转移字符 <,>或者是CDATA-->
<property name="address">
<value>
<![CDATA[<<南京>>]]>
</value>
</property>
</bean>
<bean id="orders" class="com.lsy.bean.Orders">
<constructor-arg name="oname" value="computer"></constructor-arg>
<constructor-arg name="address" value="china"></constructor-arg>
</bean>
</beans>
3.注入属性:外部bean
- 创建两个service类和dao类。
- 在service调用dao里面的方法。
- 在Spring配置文件中进行配置。
package com.lsy.bean;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
System.out.println(" service add...");
userDao.update();
}
@Override
public String toString() {
return "UserService{" +
"userDao=" + userDao +
'}';
}
}
package com.lsy.bean;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class UserDaoImpl implements UserDao{
@Override
public void update() {
System.out.println("UserDaoImpl update...");
}
}
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDaoImpl" class="com.lsy.bean.UserDaoImpl">
</bean>
<bean id="userService" class="com.lsy.bean.UserService">
<!--注入userDao对象
name属性:类里面属性名称
ref属性:创建userDao对象bean标签id值,也就是外部bean标签
-->
<property name="userDao" ref="userDaoImpl"></property>
</bean>
</beans>
Test类:
/**
* 外部bean的使用
*/
@Test
public void test4(){
//1.加载Spring的配置文件
//文件路径默认在src下。
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
//2.获取配置创建的对象
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}
4.注入属性:内部bean
- 当类与类之间存在一对多的关系时,可以使用内部bean来进行实现注入属性
- 一对多的关系:部门和员工,一个部门中有多个员工,一个员工属于一个部门
- 在员工类中设置相应部门的属性,表示所属的部门。
package com.lsy.bean;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class Emp {
private String name;
private String gender;
//员工所属的部门,使用对象的形式进行表示
private Dept dept;
public void setName(String name) {
this.name = name;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setDept(Dept dept) {
this.dept = dept;
}
}
package com.lsy.bean;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class Dept {
private String Deptname;
public void setDeptname(String deptname) {
Deptname = deptname;
}
@Override
public String toString() {
return "Dept{" +
"Deptname='" + Deptname + '\'' +
'}';
}
}
<!-- 内部bean-->
<bean id="emp" class="com.lsy.bean.Emp">
<property name="name" value="lisa"></property>
<property name="gender" value="女"></property>
<!-- 设置对象类型属性-->
<property name="dept">
<bean id="dept" class="com.lsy.bean.Dept">
<property name="deptname" value="财务部"></property>
</bean>
</property>
</bean>
Test测试类:
/**
* 内部类的使用
*/
@Test
public void test5(){
//1.加载Spring的配置文件
//文件路径默认在src下。
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
//2.获取配置创建的对象
Emp emp = context.getBean("emp", Emp.class);
System.out.println(emp);
}
5.注入属性:级联赋值
<!--级联赋值-->
<bean id="emp" class="com.atguigu.spring5.bean.Emp">
<!--设置两个普通属性-->
<property name="ename" value="lucy"></property>
<property name="gender" value="女"></property>
<!--级联赋值-->
<property name="dept" ref="dept"></property>
<!--要在Emp类中设置相应的get方法-->
<property name="dept.dname" value="技术部"></property>
</bean>
<bean id="dept" class="com.atguigu.spring5.bean.Dept">
<property name="dname" value="财务部"></property>
</bean>
6.IOC操作Bean管理(xml注入集合属性)
- 注入数组类型属性
- 注入List集合属性
- 注入Map集合类型属性
package com.lsy.bean;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @Description:
* @Author:lsy
* @Date:
*/
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;
//学生所学多门课程
private List<Course> courseList;
public void setCourseList(List<Course> courseList) {
this.courseList = courseList;
}
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;
}
public void test() {
System.out.println(Arrays.toString(courses));
System.out.println(list);
System.out.println(maps);
System.out.println(sets);
System.out.println(courseList);
}
}
package com.lsy.bean;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class Course {
private String cname; //课程名称
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Course{" +
"cname='" + cname + '\'' +
'}';
}
}
xml
<!-- 集合属性的配置-->
<bean id="stu" class="com.lsy.bean.Stu">
<!--数组类型属性的注入-->
<property name="courses">
<array>
<value>java课程</value>
<value>数据库课程</value>
</array>
</property>
<!--list类型属性注入-->
<property name="list">
<list>
<value>list1</value>
<value>list2</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>
<!--注入list集合类型,值是对象-->
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<!-- 创建多个course对象-->
<bean id="course1" class="com.lsy.bean.Course">
<property name="cname" value="Spring5"></property>
</bean>
<bean id="course2" class="com.lsy.bean.Course">
<property name="cname" value="MyBatis"></property>
</bean>
7.把节注入部分还可以提取出来
在Spring配置文件中引入名字空间util
配置bean标签
package com.lsy.bean;
import java.util.List;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class Food {
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
public void test(){
System.out.println(list);
}
}
<?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 id="listfood">
<value>apple</value>
<value>rice</value>
<value>番茄</value>
<value>tofu</value>
</util:list>
<bean id="food" class="com.lsy.bean.Food">
<property name="list" ref="listfood"></property>
</bean>
5.基于xml方式进行bean管理(FactoryBean)
1.Spring有两种类型Bean,一种是普通的bean,另外一种是工厂bean(FactoryBean)
2.普通的bean:在配置文件中定义bean类型就是返回类型(也就是说在bean标签中配置的class是什么类型返回的就是该类型的实例对象)
3.工厂bean:在配置文件中定义的bean类型可以和返回类型不一样。
第一步:创建类,让这个类作为工厂bean,实现接口FactoryBean
第二步:实现接口里面的方法,在实现的方法中定义返回的bean类型。
package com.lsy.factorybean;
import com.lsy.bean.Course;
import org.springframework.beans.factory.FactoryBean;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class MyBean implements FactoryBean<Course> {
/**
*可以增加泛型,即使在Bean标签中配置的是MyBean但是返回类型是Course类型。
* @return 返回Course
* @throws Exception
*/
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("abc");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
package com.lsy.factorybean;
import com.lsy.bean.Course;
import com.lsy.bean.Food;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class MyBeanTest {
@Test
public void test(){
//1.加载Spring的配置文件
//文件路径默认在src下。
ApplicationContext context=new ClassPathXmlApplicationContext("bean2.xml");
//2.获取配置创建的对象
Course course = context.getBean("myBean", Course.class);
System.out.println(course);
}
}
.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"
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 ">
<bean id="myBean" class="com.lsy.factorybean.MyBean">
</bean>
</beans>
6.IOC 操作Bean管理(bean作用域)
在Spring里面,可以设置创建bean实例时是单实例还是多实例
在Spring里面,默认概况下是单实例对象
如何设置是单实例还是多实例
1.在Spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
2.scope属性值
- 第一个值:默认值,singleton,表示是单实例对象
- 第二个值 prototype,表示是多实例对象
singleton和prototype区别
7.IOC操作bean管理(bean的声明周期)
生命周期:从对象创建到对象销毁的过程。
package com.lsy.timetest;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class Order {
//无参数构造
public Order() {
System.out.println("第一步 执行无参数构造创建bean实例");
}
private String oname;
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用set方法设置属性值");
}
//创建执行的初始化的方法,在配置文件中进行配置
public void initMethod() {
System.out.println("第三步 执行初始化的方法");
}
//创建执行的销毁的方法,需要在配置文件中进行配置
public void destroyMethod() {
System.out.println("第五步 执行销毁的方法");
}
}
package com.lsy.timetest;
import com.lsy.bean.Food;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Description:
* @Author:lsy
* @Date:
*/
public class TimeTest {
@Test
public void test(){
//1.加载Spring的配置文件
//文件路径默认在src下。
// ApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");
//2.获取配置创建的对象
Order order = context.getBean("order", Order.class);
System.out.println("第四步 获取创建bean实例对象");
System.out.println(order);
//手动让bean实例销毁,调用bean中配置的销毁函数
context.close();//第五步
}
}
<?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">
<bean id="order" class="com.lsy.timetest.Order" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="phone"></property>
</bean>
</beans>
如果在配置将bean添加后置处理器,那么bean的生命周期就会有七步,在初始化方法的前后,
在配置文件中配置了后置处理器之后,就会在配置文件加载的时候,为配置文件中的每一个bean都配置一个后置处理器。
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行的方法");
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行的方法");
return bean;
}
}
<bean id="myBeanPost" class="com.lsy.timetest.MyBeanPost"></bean>
8.IOC操作bean管理(xml的自动装配)
什么是自动装配
根据指定装配规则(属性名称或者属性类型),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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--实现自动装配
bean标签属性autowire,配置自动装配
autowire属性常用两个值:
byName根据属性名称注入 ,注入值bean的id值和类属性名称一样
byType根据属性类型注入
-->
<!-- 就是将Emp中的dept属性自动把id值为dept的bean标签对象自动注入 ,由于没有id值为name和gender的,因此该值为null
并且注入的Dept也是为空的-->
<bean id="emp" class="com.lsy.autotest.Emp" autowire="byName"></bean>
<!-- 按照属性的类型进行自动装配-->
<bean id="emp" class="com.lsy.autotest.Emp" autowire="byType"></bean>
<bean id="dept" class="com.lsy.autotest.Dept"></bean>
</beans>
8.IOC操作bean管理(引入外部属性文件)
1.数据库信息的配置
引入Druid的jar包;
方式一:直接配置
<!--直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
方式二,引入外部属性文件文件配置数据库连接池