文章目录
Spring(idea版)
简介
全家桶:spring
,spring boot
,springmvc
,spring cloud
初衷:解决企业开发的难度,减轻对项目模块之间的管理,类和类之间的管理,帮助开发人员创建对象,管理对象之间的关系。
核心技术:ioc
, aop
能实现模块之间,类之间的解耦合
依赖:class A中使用class B的属性或方法,叫做class A依赖class B
IOC
(Inversion of control)控制反转:是一个理论,概念,思想。
把对象的创建,赋值,管理工作都交给代码之外的容器实现,也就是对象的创建是有其他外部资源完成。
控制:创建对象,对象的属性赋值,对象之间的关系管理。
反转:把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现,由容器代替开发人员管理对象,创建对象,给属性赋值
正转:由开发人员在代码中,使用new 构造方法创建对象,开发人员主动管理对象
public static void main(String args[]){
student student = new Student(); //在代码中,创建对象 --正转
}
容器:是一个服务器软件,一个框架(spring)
为什么要使用ioc
:目的就是减少对代码的改动,也能实现不同的功能,实现解耦合
java 中创建对象有哪些方式:
- 构造方法
- 反射
- 序列化
- 克隆
- ioc :容器创建对象
- 动态代理
ioc 的体现:
servlet :
- 创建类继承
HttpServlet
- 在
web.xml
注册servlet
,使用<servlet-name> myservlet </servlet-name>
- 没有创建
servlet
对象,没有new出来,所以servlet
是tomcat
创建的。tomcat
作为容器:里面存放着servlet
对象,listener
filter
等
IOC 的技术实现:
DI是ioc的技术实现,DI叫做依赖注入:只需要在程序中提供要使用的对象就可以了,至于这个对象如何创建,赋值,查找,都由容器内部实现。
spring是使用了di实现了ioc的功能,spring底层创建对象,使用的是反射机制。
创建项目配置spring:
-
创建maven项目
-
加入maven的依赖
- spring的依赖,版本5.2.5版本
- junit依赖
-
创建类(接口和他的实现类)要自己写
和没有使用框架一样,就是普通的类
-
创建spring需要使用的配置文件
声明类的信息,这些类由spring创建和管理
通过spring的语法,完成属性的赋值
-
测试spring创建的对象
引入maven依赖pom.xml
<!-- spring的依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
创建spring配置文件
beans.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">
<!--
告诉spring创建对象
声明bean,就是告诉spring要创建某个类的对象
id:对象的自定义名称,唯一值。spring通过这个名称找到对象
class:类的全限定名称(不能是接口,因为spring是反射机制创建对象,必须使用类)
-->
<!--
spring就完成SomeService someService = new someServiceImpl();
spring是把创建好的对象放入到map中,spring框架有一个map存放对象的。
springMap.put(id的值,对象)
例如:springMap.put("someService", new SomeServiceImpl());
一个bean标签声明一个对象
-->
<bean id="someService" class="org.example.service.impl.SomeServiceImpl" />
</beans>
<!--
spring的配置文件
1.beans:是跟标签,spring把java对象称为bean
2.spring-beans.xsd 是约束文件,和mybatis指定dtd是一样的
-->
创建容器对象ApplicationContext
在测试类中创建ApplicationContext
对象
// 测试spring的使用
@Test
public void test02() {
// 使用spring容器创建的对象
// 1.指定spring配置文件的名称
String config = "beans.xml";
// 2.创建表示spring容器的对象,ApplicationContext
// ApplicationContext就是表示Spring容器,通过容器获取对象了
// ClassPathXmlApplicationContext表示从类路径中加载spring的配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
// 从容器中获取某个对象,你要调用对象的方法
// getBean("配置文件中bean的id值")
SomeService service = (SomeService) ac.getBean("someService");
// 使用spring创建好的对象
service.doSome();
}
ApplicationContext ac = new ClassPathXmlApplicationContext(config)
读取spring的配置文件
ac.getBean("someService")
使用spring中配置的某个类并创建它的对象
service.doSome()
使用对象
spring创建对象的时机
spring默认创建对象的时间:在创建spring的容器时,会创建配置文件中的所有的对象
获取容器中对象信息的API举例
获取容器中定义对象的数量
@Test
public void test03() {
String config = "beans.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
// 使用spring提供的方法,获取容器中定义对象的数量
int nums = ac.getBeanDefinitionCount();
System.out.println("在容器中定义的对象的数量是:" + nums);
}
获取容器中对象的每个对象的名称
@Test
public void test03() {
String config = "beans.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
// 容器中每个定义的对象的名称
String names[] = ac.getBeanDefinitionNames();
for(String name:names) {
System.out.println(name);
}
}
spring创建非自定义对象
spring能创建一个非自定义的对象吗?创建一个已存在的某个类的对象。是可以的
<bean id="myDate" class="java.util.Date" />
设值注入概念
DI:依赖注入,表示创建对象,给属性赋值
DI的实现有两种:
- 在spring的配置文件中,使用标签和属性完成,叫做基于XML的di实现
- 使用spring中的注解,完成赋值,叫做基于注解的id实现
DI的语法分类:
- set注入(设置注入):spring调用类的set方法,在set方法可以实现属性的赋值,百分之80都是使用set注入
- 构造注入,spring调用类的有参构造方法,创建对象,在构造方法中完成赋值
简单类型的set注入
set注入(设置注入):spring调用类的set方法,你可以在set方法中完成赋值
<bean id="xx" class="yyyy">
<property name="属性名字" value="此属性的值" />
一个property只能给一个属性赋值
<property ... />
</bean>
它会去调用类的set方法去帮你赋值
<bean id="myPerson" class="org.example.set.Person" >
<property name="age" value="10" />
<property name="name" value="李四" />
</bean>
类中set方法设置输出
测试类输出
设值注入的注意事项
需要有set方法,没有set方法会报错
Bean property 'xxx' is not writable or has an invalid setter method
引用类型的设值注入(原始方法)
引用类型的设值注入跟简单类型的设值注入大同小异。
格式:引用类型的set注入:spring调用类的set方法
<bean id="xx" class="yyyy">
<property name="属性名字" ref="bean的id(对象的名称)" />
</bean>
举例:
School类
Person类(其中有个引用类型school)
xml
配置
测试方法测试spring容器
构造注入
因为spring默认调用的无参构造函数,所以如果要使用构造函数赋值,那么就要在xml
文件中增加配置,让spring调用有参构造方法去赋值。
spring调用类的有参数构造方法,在创建对象的同时,在构造方法中给属性赋值
构造注入使用<constructor-arg>
标签
<constructor-arg>
标签属性:
name
:表示构造方法的形参名
index
:表示构造方法的参数的位置,参数从左往右位置是0,1,2的顺序
value
:构造方法的形参类型是简单类型的,使用value,
ref
:构造方法的形参类型是引用类型的,使用ref
例:
Person类中增加有参构造函数:
/**
* 有参构造方法
* @param age
* @param name
* @param school
*/
public Person(int age, String name, School school) {
this.age = age;
this.name = name;
this.school = school;
System.out.println("==Person类的有参构造方法==");
}
XML配置文件增加调用有参注入的配置:
<bean id="myPerson" class="org.example.set.Person" >
<constructor-arg name="age" value="23" />
<constructor-arg name="name" value="张三" />
<constructor-arg name="school" ref="mySchool" />
</bean>
<!-- 声明School对象 -->
<bean id="mySchool" class="org.example.set.School" >
<property name="name" value="大连海事大学" />
<property name="address" value="大连市甘井子区凌海路1号" />
</bean>
测试类输出:
构造注入创建文件对象
XML文件配置:
<bean id="myFile" class="java.io.File" >
<constructor-arg name="parent" value="D:\Iprogram\java_program\spring_01\hello_spring" />
<constructor-arg name="child" value="pom.xml" />
</bean>
增加测试类方法:
@Test
public void Test04() {
String config = "set/setBeans.xml";
ApplicationContext ac2 = new ClassPathXmlApplicationContext(config);
// 从容器中拿到File对象
File fl = (File) ac2.getBean("myFile");
System.out.println(fl.getName());
}
测试结果
自动注入
引用类型的自动注入:spring框架根据某些规则可以给引用类型赋值,不用你再给引用类型赋值了
使用的规则常用的是byName
,byType
byName
byName(按名称注入)
:Java类中引用类型的属性名和spring容器中(配置文件)的id名称一样,且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型
语法:
<bean id="xx" class="yyy" autowire="byName">简单类型属性赋值</bean>
例:
<bean id="myPerson" class="org.example.set.Person" autowire="byName" >
<property name="age" value="23" />
<property name="name" value="李四" />
<!--<property name="school" ref="mySchool" />-->
</bean>
<!-- 声明School对象,这里的id就不能随机设置,而是跟属性名相同 -->
<bean id="school" class="org.example.set.School" >
<property name="name" value="大连海事大学" />
<property name="address" value="大连市甘井子区凌海路1号" />
</bean>
这里的引用类型的配置id就不能随机设置,而是跟类中引用类型的属性名相同
byType
byType(按类型注入)
:java类中引用类型的数据类型和spring容器中(配置文件)的class属性是同源关系的,这样的bean能够赋值给引用类型
同源就是一类的意思:
- java类中引用类型的数据类型和bean的class的值是一样的
- java类中引用类型的数据类型和bean的class的值是父子类关系的。
- java类中引用类型的数据类型和bean的class的值接口和实现类关系的
注意:在byType中,在xml配置文件中声明bean只能由一个符合条件的,多余一个会报错
语法:
<bean id="xx" class="yyy" autowire="byType">简单类型属性赋值</bean>
例:
<bean id="myPerson" class="org.example.set.Person" autowire="byType" >
<property name="age" value="23" />
<property name="name" value="李四" />
<!--<property name="school" ref="mySchool" />-->
</bean>
<!-- 声明School对象,这里的org.example.set.School和Person中school的类型是一致的,所以spring就使用了mySchool -->
<bean id="mySchool" class="org.example.set.School" >
<property name="name" value="大连海事大学" />
<property name="address" value="大连市甘井子区凌海路1号" />
</bean>
例2:如果DalianHaishi类为School的子类
<bean id="myPerson" class="org.example.set.Person" autowire="byType" >
<property name="age" value="23" />
<property name="name" value="李四" />
<!--<property name="school" ref="mySchool" />-->
</bean>
<!-- 声明School对象,这里的org.example.set.DalianHaishi为School的子类,所以spring就使用了dalianSchool -->
<bean id="dalianSchool" class="org.example.set.DalianHaishi" >
<property name="name" value="大连海事大学" />
<property name="address" value="大连市甘井子区凌海路1号" />
</bean>
例3:现有个Dao接口,DaoImpl实现类,Person里面有个属性为Dao接口类型的
<!-- 实现类 -->
<bean id="oracleDao" class="org.example.set.OracleDaoImpl" autowire="byType" ></bean>
<!-- 接口 -->
<bean id="userService" class="org.example.set.oracleDao" >
<property name="dao" ref="oracleDao" />
</bean>
多配置文件
优势:
- 每个文件的大小比一个文件要小很多,效率高
- 避免多人竞争带来的冲突
分配方式:
- 按功能模块,一个模块一个配置文件
- 按类的功能,数据库相关的配置一个文件配置文件,做事务的功能一个配置文件,做service功能的一个配置文件
spring主配置文件:包含其他的配置文件,一般是不定义对象的
语法:
<import resource="其他配置文件的路径" />
关键字:“classpath”:表示类路径(class文件所在的目录),在spring的配置文件中要指定其他文件的路径,需要使用classpath,告诉spring到哪去加载读取文件
例:
spring-student.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">
<bean id="mySchool" class="org.example.student.Student">
<property name="age" value="24" />
<property name="name" value="小王" />
</bean>
</beans>
spring-school.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">
<bean id="mySchool" class="org.example.school.School">
<property name="managerName" value="王刚" />
<property name="name" value="大连海事大学" />
</bean>
</beans>
spring-files.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">
<import resource="classpath:school/spring-school.xml" />
<import resource="classpath:student/spring-student.xml" />
</beans>
注解的使用※
通过注解完成java对象的创建,属性赋值
使用注解的步骤:
- 加入maven的依赖,spring-context,在你加入spring-context的同时,间接加入spring-aop的依赖,使用注解必须使用spring-aop的依赖
- 在类中加入spring的注解
- 在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你项目的位置
声明组件扫描器(component-scan)
<context:component-scan base-package="" />
base-package
:指定注解在你项目中的包名。
component-scan
:工作方式:spring会扫描遍历base-package指定的包,把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象,或给属性赋值。
在加入了component-scan标签,配置文件的变化:
- 加入一个新的约束文件spring-context.xsd
- 给这个新的约束文件起个命名空间的名称
指定多个包的三种方式:
使用多次组件扫描器,指定不同的包
<context:component-scan base-package="org.example.test.component1" />
<context:component-scan base-package="org.example.test.component2" />
<context:component-scan base-package="org.example.test.component3" />
使用分割符(;或,)分隔多个包名
<context:component-scan base-package="org.example.test.component1;org.example.test.component2;org.example.test.component3" />
指定父包
<context:component-scan base-package="org.example.test" />
学习注解:
-
@Component
:创建对象的,等同于的功能属性:value 就是对象的名称,也就是bean的id值
value的值是唯一的,创建的对象在整个spring容器中就一个
位置:在类的上面
@Component(value = "myStudent") 等同于 <bean id="myStudent" class="cn.iceseasyh.Student">
如果value不指定名称,则默认使用的是类名称(首字母小写)
-
@Respotory
-
@Service
-
@Controller
-
@Value
:给简单类型的属性赋值属性:value是String类型的,表示简单类型的属性值。
位置:
- 在属性定义的上面,无需set方法,推荐使用
@Value(value="张飞") private String name; @Value(value="中国") private String address;
- 在set方法的上面
@Value(value="张飞") public void setName(String name) { this.name = name; }
-
@Autowired
:给引用类型赋值,使用的是自动注入原理,支持byName,byType,它默认使用byType自动注入如果要使用byName方式,需要做的是:
- 在属性上面加入
@Autowired
- 在属性上面加入
@Qualifier(value="bean的id")
,表示使用指定名称的bean完成赋值
@Autowired @Qualifier(value = "myDemo") private ComponentDemo componentDemo;
位置:
-
在属性定义的上面,无需set方法,推荐使用
@Autowired private ComponentDemo componentDemo;
-
在set方法的上面,不推荐
@Autowired
的required
属性:是一个boolean类型的,默认truerequired=true
:表示引用类型赋值失败,程序报错,并终止执行required=false
:引用类型如果赋值失败,程序正常执行,引用类型是null建议不要使用false,用true可以提前暴露问题,错误。
- 在属性上面加入
-
@Resource
:来自于JDK的注解,不是spring提供的,spring提供了对jdk中@Resource
注解的支持。Resource
注解既可以按名称匹配Bean,也可以按类型匹配Bean,默认是按名称注入。使用该注解,要求JDK必须是6及以上版本的。它自动注入的逻辑是先使用byName,如果byName赋值失败,再使用byType进行赋值@Resource private ComponentDemo componentDemo;
位置:
- 在属性定义的上面,无序set方法,推荐使用
- 在set方法的上面
对于DI使用注解,将不再需要在spring配置文件中声明bean实例,spring中使用注解,需要在原有spring运行环境基础上再做一些改变。
需要在spring配置文件中配置组件扫描器,用于在指定的基本包中扫描注解
通过spring的注解完成java对象的创建,属性。代替xml文件
实现步骤:
- 加入依赖
- 创建类,在类中加入注解
- 创建spring的配置文件,声明组件扫描器的标签,指名注解在你的项目中的位置
- 使用注解创建对象,创建容器ApplicationContext
多注解项目分层
以下三个注解的使用语法和@Component
一样的,都能创建对象,但是这三个注解还有额外的功能。
@Respotory
:用在持久层类上面,跟@Component
一样是创建对象的,放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的@Service
:用在业务层类的上面,跟@Component
一样是创建对象的,放在service的实现类上面,创建service对象,service对象是做业务处理的,可以有事务等功能。@Controller
:用在控制器的上面,跟@Component
一样是创建对象的,放在控制器(处理器)类的上面,创建控制器对象的,控制器对象能够接收用户提交的参数,显示请求的处理结果。