前面的博客中已经介绍了Spring的创建和使用第一版,第一版现在已经不怎么在使用了。下面将介绍目前Spring的常见用法。
Spring中想要更简单的存储和读取对象的核心方法是使用注解。
Spring的创建和使用
1.先创建出Spring项目出来
2.存储Bean对象
3.获取Bean对象
创建Spring项目
和1.0一样创建出一个Spring项目出来并在pom.xml文件中添加核心jar包,以及创建一个启动类:
存储Bean对象
在resources目录下面配置Spring.xml文件,Spring.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"
xmlns:content="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
https://www.springframework.org/schema/context/spring-context.xsd">
//下面是配置文件的扫描路径,根据自己的文件所在的位置来处理这个路径
<content:component-scan base-package="com.user"></content:component-scan>
</beans>
上面是配置文件的扫描路径,根据自己的文件所在的位置来处理这个路径,像我在com.user.Controller目录下面创建了一个控制层文件UserController,那么我的扫描路径就可以写成com.user,这样设置以后Spring在扫描文件的时候,他就会去该目录下面查看。这里的写法不是唯一的,你也可以将路径写大一点,比如直接com也可以,但是不推荐。
给存储Bean对象添加注解
想要将对象存储在Spring中,就得给对象添加注解,二注解又分两种:类注解、方法注解
类注解
顾名思义就是在类的前面加上注解,像下面这样:
@Controller
public class UserController {
public void Hi(String name){
System.out.println("Hi:"+name);
}
}
类注解包括:@Controller(控制器存储)、@Service(服务存储)、@Repository(仓库存储)、@Component(组件存储)、@Configuration(配置存储)
首先我们的明白,我们再写一个Spring项目的时候,因为涉及到前后端的交互还有和数据库的交互。各个目录之间的层级关系一定要明确,关于层级关系,它相当于是编程规范,实行这种规范可以方便开发和维护代码,具体的东西还请自己去了解。
Controller处在控制层,主要负责前端数据的校验 ;
Service处在服务层,主要负责数据的处理还有组装;
Repository处在存储层,主要负责数据库中表的操作,以及将数据存储在数据库中;
Configuration处在配置层,主要负责管理系统的配置信息;
Component处在组件层,主要负责存放编写Spring项目所需要的公共组件。
它们之间的关系如下图:
其中
@Controller(控制器存储)、@Service(服务存储)、@Repository(仓库存储)、@Configuration(配置存储)都是@Component(组件存储)的子类
方法注解
在方法的上面加上注解,方法注解必须配合类注解才能一起使用(因为Spring在扫描的时候是以类为单位来扫描的,如果类上面不加上注解,就扫描不到) :
@Controller
public class UserController {
@Bean
public User GoodBey(){
User user = new User();
user.setId(1);
user.setName("韩梅梅");
return user;
}
}
public class User {
private int Id;
private String name;
public void setId(int id) {
Id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"Id=" + Id +
", name='" + name + '\'' +
'}';
}
}
现在先来看一下它们的使用:
现在来详细讨论一下这两类注解:
方法注解目前包括:@Bean
在使用方法注解的时候要注意:方法注解必须配合类注解才能使用。
在我们写方法注解的时候,有时方法名可能很长,这时可以给Bean对象进行重命名操作,但是重命名以后就不能再使用方法名:
@Bean(name = "GB")
public User GoodBey(){
User user = new User();
user.setId(1);
user.setName("韩梅梅");
return user;
}
关于Bean的命名
通常在使用注解的时候,要求在写类名的时候要采用大驼峰,而读取类名的时候要求类名的首字母要小写。如果类名中首个字母和第二个字母都是大写,那么在读取类名的时候就按照类名来读就可以了,这个时候不能在采用类名首字母小写,否者会报错:
我们查看Spring里面的原码就知道原因了:
在IDEA中按查找类的快捷键ctrl+N,找到AnnotationBeanNameGenerator这个类:
然后查看这个方法:
从上面就可以解释为什么会报错了
获取Bean对象(对象注入)
获取Bean对象也叫对象注入,是把对象取出放到某个类中。
对象注入的实现有以下3种方式:
1.属性注入
2.Setter注入
3.构造方法注入
属性注入
属性注入就是在属性上面添加@Autowired注解。将UserService类注入到UserController类中,像下面这样:
@Service
public class UserService {
/*
* 根据ID获取用户数据
*/
public User findUserById(Integer id){
User user = new User();
if(id==1){
user.setId(1);
user.setName("张三");
}else{
user.setId(2);
user.setName("李四");
}
return user;
}
public void Hi(String name){
System.out.println("Hi:"+name);
}
}
@Controller
public class UserController {
//1.属性注入,从Spring中获取一个对象,并注入到当前类
@Autowired
private UserService userService;
public User findSuerById(Integer id){
return userService.findUserById(id);
}
public void Hi(String name){
System.out.println("Hi:"+name);
}
}
public class App {
public static void main(String[] args) {
//1.获取到Spring的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
//2.加载类注解Bean对象
UserController userController = context.getBean("userController", UserController.class);
//3.使用它里面的方法
System.out.println(userController.findSuerById(1));
}
}
特殊类型属性注入
对象类型属性注入
创建两个类:部门类和员工类
package com.atguigu.spring6.iocxml.ditest;
import java.util.List;
//部门类
public class Dept {
private String dname;
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public void info() {
System.out.println("部门名称:"+dname);
}
}
package com.atguigu.spring6.iocxml.ditest;
import java.util.Arrays;
//员工类
public class Emp {
//对象类型属性:员工属于某个部门
private Dept dept;
//员工名称
private String ename;
//员工年龄
private Integer age;
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void work() {
System.out.println(ename+"emp work....."+age);
dept.info();
}
}
通过外部Bean注入
<?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
1 创建两个类对象:dept 和 emp
2 在emp的bean标签里面,使用property引入dept的bean
-->
<bean id="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="安保部"></property>
</bean>
<bean id="emp" class="com.atguigu.spring6.iocxml.ditest.Emp">
<!--注入对象类型属性
private Dept dept;
-->
<property name="dept" ref="dept"></property>
<!--普通属性注入-->
<property name="ename" value="lucy"></property>
<property name="age" value="50"></property>
</bean>
</beans>
package com.atguigu.spring6.iocxml.ditest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDept {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-dilist.xml");
//员工对象
Dept dept = context.getBean("emp", Dept.class);
dept.info();
}
}
内部bean注入
<?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注入-->
<bean id="emp2" class="com.atguigu.spring6.iocxml.ditest.Emp">
<!--普通属性注入-->
<property name="ename" value="mary"></property>
<property name="age" value="20"></property>
<!--内部bean-->
<property name="dept">
<bean id="dept2" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="财务部"></property>
</bean>
</property>
</bean>
</beans>
级联属性赋值
<?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="dept3" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="技术研发部"></property>
</bean>
<bean id="emp3" class="com.atguigu.spring6.iocxml.ditest.Emp">
<property name="ename" value="tom"></property>
<property name="age" value="30"></property>
<property name="dept" ref="dept3"></property>
<property name="dept.dname" value="测试部"></property>
</bean>
</beans>
数组类型注入
package com.atguigu.spring6.iocxml.ditest;
import java.util.Arrays;
//员工类
public class Emp {
//对象类型属性:员工属于某个部门
private Dept dept;
//员工名称
private String ename;
//员工年龄
private Integer age;
//爱好
private String[] loves;
public void work() {
System.out.println(ename+"emp work....."+age);
dept.info();
System.out.println(Arrays.toString(loves));
}
public String[] getLoves() {
return loves;
}
public void setLoves(String[] loves) {
this.loves = loves;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
<?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="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="技术部"></property>
</bean>
<bean id="emp" class="com.atguigu.spring6.iocxml.ditest.Emp">
<!--普通属性-->
<property name="ename" value="lucy"></property>
<property name="age" value="20"></property>
<!--对象类型属性-->
<property name="dept" ref="dept"></property>
<!--数组类型属性-->
<property name="loves">
<array>
<value>吃饭</value>
<value>睡觉</value>
<value>敲代码</value>
</array>
</property>
</bean>
</beans>
package com.atguigu.spring6.iocxml.ditest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestEmp {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-diarray.xml");
//员工对象
Emp emp = context.getBean("emp", Emp.class);
emp.work();
}
}
List集合类型属性注入
package com.atguigu.spring6.iocxml.ditest;
import java.util.List;
//部门类
public class Dept {
//一个部门有很多员工
private List<Emp> empList;
private String dname;
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public List<Emp> getEmpList() {
return empList;
}
public void setEmpList(List<Emp> empList) {
this.empList = empList;
}
public void info() {
System.out.println("部门名称:"+dname);
for (Emp emp:empList) {
System.out.println(emp.getEname());
}
}
}
<?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="empone" class="com.atguigu.spring6.iocxml.ditest.Emp">
<property name="ename" value="lucy"></property>
<property name="age" value="20"></property>
</bean>
<bean id="emptwo" class="com.atguigu.spring6.iocxml.ditest.Emp">
<property name="ename" value="mary"></property>
<property name="age" value="30"></property>
</bean>
<bean id="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
<property name="dname" value="技术部"></property>
<property name="empList">
<list>
<ref bean="empone"></ref>
<ref bean="emptwo"></ref>
</list>
</property>
</bean>
</beans>
package com.atguigu.spring6.iocxml.ditest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestEmp {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-diarray.xml");
//员工对象
Emp emp = context.getBean("emp", Emp.class);
emp.work();
}
}
Map集合类型属性注入
package com.atguigu.spring6.iocxml.dimap;
import java.util.List;
import java.util.Map;
public class Student {
private Map<String,Teacher> teacherMap;
private String sid;
private String sname;
public void run() {
System.out.println("学生编号: "+sid+ "学生名称:"+sname);
System.out.println(teacherMap);
}
public Map<String, Teacher> getTeacherMap() {
return teacherMap;
}
public void setTeacherMap(Map<String, Teacher> teacherMap) {
this.teacherMap = teacherMap;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
}
package com.atguigu.spring6.iocxml.dimap;
public class Teacher {
private String teacherId;
private String teacherName;
public String getTeacherId() {
return teacherId;
}
public void setTeacherId(String teacherId) {
this.teacherId = teacherId;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
@Override
public String toString() {
return "Teacher{" +
"teacherId='" + teacherId + '\'' +
", teacherName='" + teacherName + '\'' +
'}';
}
}
<?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">
<!--
1 创建两个对象
2 注入普通类型属性
3 在学生bean注入map集合类型属性
-->
<bean id="teacherone" class="com.atguigu.spring6.iocxml.dimap.Teacher">
<!--注入普通类型属性-->
<property name="teacherId" value="100"></property>
<property name="teacherName" value="西门讲师"></property>
</bean>
<bean id="teachertwo" class="com.atguigu.spring6.iocxml.dimap.Teacher">
<!--注入普通类型属性-->
<property name="teacherId" value="200"></property>
<property name="teacherName" value="上官讲师"></property>
</bean>
<bean id="student" class="com.atguigu.spring6.iocxml.dimap.Student">
<!--注入普通类型属性-->
<property name="sid" value="2000"></property>
<property name="sname" value="张三"></property>
<!--在学生bean注入map集合类型属性-->
<property name="teacherMap">
<map>
<entry>
<key>
<value>10010</value>
</key>
<ref bean="teacherone"></ref>
</entry>
<entry>
<key>
<value>10086</value>
</key>
<ref bean="teachertwo"></ref>
</entry>
</map>
</property>
</bean>
</beans>
package com.atguigu.spring6.iocxml.dimap;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestStu {
@Test
public void testStu() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-dimap.xml");
Student student = context.getBean("student", Student.class);
student.run();
}
}
引用集合类型Bean注入
package com.atguigu.spring6.iocxml.dimap;
import java.util.List;
import java.util.Map;
public class Student {
private List<Lesson> lessonList;
private Map<String,Teacher> teacherMap;
private String sid;
private String sname;
public void run() {
System.out.println("学生编号: "+sid+ "学生名称:"+sname);
System.out.println(teacherMap);
System.out.println(lessonList);
}
public List<Lesson> getLessonList() {
return lessonList;
}
public void setLessonList(List<Lesson> lessonList) {
this.lessonList = lessonList;
}
public Map<String, Teacher> getTeacherMap() {
return teacherMap;
}
public void setTeacherMap(Map<String, Teacher> teacherMap) {
this.teacherMap = teacherMap;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
}
package com.atguigu.spring6.iocxml.dimap;
public class Lesson {
private String lessonName;
public String getLessonName() {
return lessonName;
}
public void setLessonName(String lessonName) {
this.lessonName = lessonName;
}
@Override
public String toString() {
return "Lesson{" +
"lessonName='" + lessonName + '\'' +
'}';
}
}
<?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/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
1 创建三个对象
2 注入普通类型属性
3 使用util:类型 定义
4 在学生bean引入util:类型定义bean,完成list、map类型属性注入
-->
<bean id="student" class="com.atguigu.spring6.iocxml.dimap.Student">
<property name="sid" value="10000"></property>
<property name="sname" value="lucy"></property>
<!--注入list、map类型属性-->
<property name="lessonList" ref="lessonList"></property>
<property name="teacherMap" ref="teacherMap"></property>
</bean>
<util:list id="lessonList">
<ref bean="lessonone"></ref>
<ref bean="lessontwo"></ref>
</util:list>
<util:map id="teacherMap">
<entry>
<key>
<value>10010</value>
</key>
<ref bean="teacherone"></ref>
</entry>
<entry>
<key>
<value>10086</value>
</key>
<ref bean="teachertwo"></ref>
</entry>
</util:map>
<bean id="lessonone" class="com.atguigu.spring6.iocxml.dimap.Lesson">
<property name="lessonName" value="java开发"></property>
</bean>
<bean id="lessontwo" class="com.atguigu.spring6.iocxml.dimap.Lesson">
<property name="lessonName" value="前端开发"></property>
</bean>
<bean id="teacherone" class="com.atguigu.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="100"></property>
<property name="teacherName" value="西门讲师"></property>
</bean>
<bean id="teachertwo" class="com.atguigu.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="200"></property>
<property name="teacherName" value="欧阳讲师"></property>
</bean>
</beans>
package com.atguigu.spring6.iocxml.dimap;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestStu {
@Test
public void testStu() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-diref.xml");
Student student = context.getBean("student", Student.class);
student.run();
}
}
P命令空间注入
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空间注入-->
<bean id="studentp" class="com.atguigu.spring6.iocxml.dimap.Student"
p:sid="100" p:sname="mary" p:lessonList-ref="lessonList" p:teacherMap-ref="teacherMap">
</bean>
<!--
1 创建三个对象
2 注入普通类型属性
3 使用util:类型 定义
4 在学生bean引入util:类型定义bean,完成list、map类型属性注入
-->
<bean id="student" class="com.atguigu.spring6.iocxml.dimap.Student">
<property name="sid" value="10000"></property>
<property name="sname" value="lucy"></property>
<!--注入list、map类型属性-->
<property name="lessonList" ref="lessonList"></property>
<property name="teacherMap" ref="teacherMap"></property>
</bean>
<util:list id="lessonList">
<ref bean="lessonone"></ref>
<ref bean="lessontwo"></ref>
</util:list>
<util:map id="teacherMap">
<entry>
<key>
<value>10010</value>
</key>
<ref bean="teacherone"></ref>
</entry>
<entry>
<key>
<value>10086</value>
</key>
<ref bean="teachertwo"></ref>
</entry>
</util:map>
<bean id="lessonone" class="com.atguigu.spring6.iocxml.dimap.Lesson">
<property name="lessonName" value="java开发"></property>
</bean>
<bean id="lessontwo" class="com.atguigu.spring6.iocxml.dimap.Lesson">
<property name="lessonName" value="前端开发"></property>
</bean>
<bean id="teacherone" class="com.atguigu.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="100"></property>
<property name="teacherName" value="西门讲师"></property>
</bean>
<bean id="teachertwo" class="com.atguigu.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="200"></property>
<property name="teacherName" value="欧阳讲师"></property>
</bean>
</beans>
package com.atguigu.spring6.iocxml.dimap;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestStu {
@Test
public void testStu() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-diref.xml");
Student student = context.getBean("studentp", Student.class);
student.run();
}
}
注入外部文件
1.引入数据库相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring6</artifactId>
<groupId>com.atguigu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring6-ioc-xml</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!-- 数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.15</version>
</dependency>
</dependencies>
</project>
2.创建外部属性文件(properties格式——定义数据信息:用户名、密码、地址等)
jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/spring?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
3.创建spring配置文件,引入context命令空间(引入属性文件,使用表达式完成注入)
package com.atguigu.spring6.iocxml.jdbc;
import com.alibaba.druid.pool.DruidDataSource;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestJdbc {
@Test
public void demo() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-jdbc.xml");
DruidDataSource dataSource = context.getBean(DruidDataSource.class);
System.out.println(dataSource.getUrl());
}
}
Setter注入
基于XML方式的Setter注入
package com.atguigu.spring6.iocxml.di;
public class Book {
private String bname;
private String author;
private String others;
public Book() {
}
//生成set方法
public String getBname() {
return bname;
}
public String getOthers() {
return others;
}
public void setOthers(String others) {
this.others = others;
}
public void setBname(String bname) {
this.bname = bname;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"bname='" + bname + '\'' +
", author='" + author + '\'' +
", others='" + others + '\'' +
'}';
}
}
<?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">
<!--1 set方法注入-->
<bean id="book" class="com.atguigu.spring6.iocxml.di.Book">
<property name="bname" value="前端开发"></property>
<property name="author" value="尚硅谷"></property>
<property name="others">
<null/>
</property>
</bean>
</beans>
package com.atguigu.spring6.iocxml.di;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestBook {
@Test
public void testSetter() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-di.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
}
通过获得setter方法,然后在set方法上面加上@Autowired,将UserService类注入到UserController类中,像下面这样:
@Controller
public class UserController2 {
private UserService userService;
//1.Setter注入
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public User findUserById(Integer id){
return userService.findUserById(id);
}
}
public class App {
public static void main(String[] args) {
//1.获取到Spring的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
//2.加载类注解Bean对象
UserController2 controller2 = context.getBean("userController2", UserController2.class);
//3.使用它里面的方法
System.out.println(controller2.findUserById(1));
}
}
利用Setter注入方式的步骤:1.定义属性 、2.生成属性setter方法、3.给setter方法添加@Autowired注解
构造方法注入
基于XML方式的构造器注入
package com.atguigu.spring6.iocxml.di;
public class Book {
private String bname;
private String author;
private String others;
public Book() {
System.out.println("无参数构造执行了...");
}
//有参数构造方法
public Book(String bname, String author) {
System.out.println("有参数构造执行了...");
this.bname = bname;
this.author = author;
}
//生成set方法
public String getBname() {
return bname;
}
public String getOthers() {
return others;
}
public void setOthers(String others) {
this.others = others;
}
public void setBname(String bname) {
this.bname = bname;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"bname='" + bname + '\'' +
", author='" + author + '\'' +
", others='" + others + '\'' +
'}';
}
}
<?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">
<!--2 构造器注入-->
<bean id="bookCon" class="com.atguigu.spring6.iocxml.di.Book">
<constructor-arg name="bname" value="java开发"></constructor-arg>
<constructor-arg name="author" value="尚硅谷"></constructor-arg>
</bean>
</beans>
package com.atguigu.spring6.iocxml.di;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestBook {
@Test
public void testConstructor() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-di.xml");
Book book = context.getBean("bookCon", Book.class);
System.out.println(book);
}
}
构造方法注入是在类的构造方法中注入,将UserService类注入到UserController类中,像下面这样:
@Controller
public class UserController3 {
private UserService userService;
@Autowired
public UserController3(UserService userService) {
this.userService = userService;
}
public User findUserById(Integer id){
return userService.findUserById(id);
}
}
public class App {
public static void main(String[] args) {
//1.获取到Spring的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
//2.加载类注解Bean对象
UserController3 userController3 = context.getBean("userController3", UserController3.class);
//3.使用它里面的方法
System.out.println(userController3.findUserById(1));
}
}
注意:在使用构造方法注入的时候,如果类中只存在一个构造方法,那么可以省略这个构造方法上面的注解@Autowired,但是两个和两个以上的构造方法的时候@Autowired不能省略。
三种注解优缺点:
- 属性注解的优点是简洁,使用方便;缺点是只能用于IoC容器,如果是非IoC容器用属性注入,则会报空指针异常,还有就是不能注入不可变对象(final修饰的对象);
- Setter方式注入的优点符合单一设计原则;缺点是不能注入不可变对象(final修饰的对象)而且通用性不如构造方法;
- 构造方法注入的优点是通用性好,在使用之前一定能保证注入的类不为空,而且可以注入不可变对象;缺点是如果有多个注入会显得比较臃肿;
@Resource
我们在使用依赖注入的时候,不光只有@Autowired一种方式,还有另一种方式@Resource
@ Autowired和@Resource的区别
- 它们两个出身不同,@Autowired来自于Spring,而@Resource来自于JDK的注解;
- @Resource注解不能使用在构造方法上,而@Autowired可以;
- 使用时设置的参数不同,@Resource对于@Autowired来说支持更多的参数设置,比如name,利用这一点可以给类名起别名。
- @Autowired默认是按照类型进行注入,@Resource默认是按照名称进行注入,如果按名称找不到要注入的属性,则按照类型进行注入
@Component
public class UserBean {
@Bean(name = "GB1")
public User GoodBey1(){
User user = new User();
user.setId(1);
user.setName("韩梅梅");
return user;
}
@Bean(name = "GB2")
public User GoodBey2(){
User user = new User();
user.setId(2);
user.setName("李华");
return user;
}
}
@Controller
public class UserController4 {
@Resource(name="GB1")
private User user;
public User findClient(){
return user;
}
}
public class App {
public static void main(String[] args) {
//1.获取到Spring的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
//2.加载类注解Bean对象
UserController4 userController4 = context.getBean("userController4", UserController4.class);
//3.使用它里面的方法
System.out.println(userController4.findClient());
}
}
同一个类型多个Bean报错的问题
之前在1.0版本中,我们讨论过获取Bean的时候,对于多个对象的同一种类型的Bean获取会报错
比如像下面这样:
@Component
public class UserBean {
@Bean(name = "GB1")
public User GoodBey1(){
User user = new User();
user.setId(1);
user.setName("韩梅梅");
return user;
}
@Bean(name = "GB2")
public User GoodBey2(){
User user = new User();
user.setId(2);
user.setName("李华");
return user;
}
}
@Controller
public class UserController5 {
@Autowired
private User user;
public User findClient(){
return user;
}
}
import com.user.Controller.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
//1.获取到Spring的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
//2.加载类注解Bean对象
UserController5 userController5 = context.getBean("userController5", UserController5.class);
//3.使用它里面的方法
System.out.println(userController5.findClient());
}
}
在分析出现上述错误之前,我们的先明白一个事情,那就是@Autowired和@Resource两个注解获取Bean对象是通过两种方式来获取的:
1.通过类型来获取
context.getBean(UserController5.class)
2.通过名称来获取
context.getBean("userController5")
如果根据名称来获取,获取不到,那么这两个注解就会去根据类型来获取,如果都获取不到就会报错。
现在再来分析上面报错的原因,在UserBean类里面,有两个方法,这两个方法的类型都是User,其中一个方法名是GB1,另一个是GB2。而我们在UserController5类里面将User类通过属性注入的方式注入进来,但是我们取Bean的名称为user,@Autowired就会在com.user目录下面去找这个Bean对象,很明显是找不到的。然后@Autowired就会采用类型User的方式来找,在UserBean类里面他发现有两个User类型的Bean对象,这是它就不知道调用那一个了,所以就会报错。
通过上面的分析,我们就可以在UserController5类里面修改Bean的名称,比如改为GB1:
@Controller
public class UserController5 {
@Autowired
private User GB1;
public User findClient(){
return GB1;
}
}
但是如果现在不能修改Bean对象的名称,那就通过一下的方法来解决了:
使用@Resource(name="指定Bean的名称")
这种方式在介绍@Resource就演示过了,所以不在演示。
使用@Autowired+@Qualifier(value = "")
@Controller
public class UserController5 {
@Autowired
@Qualifier(value = "GB1")
private User user;
public User findClient(){
return user;
}
}
Bean的作用域
<?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">
<!--通过scope属性配置单实例 多实例-->
<bean id="orders" class="com.atguigu.spring6.iocxml.scope.Orders"
scope="singleton"></bean>
</beans>
package com.atguigu.spring6.iocxml.scope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestOrders {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-scope.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println(orders);
Orders orders1 = context.getBean("orders", Orders.class);
System.out.println(orders1);
}
}
<?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">
<!--通过scope属性配置单实例 多实例-->
<bean id="orders" class="com.atguigu.spring6.iocxml.scope.Orders"
scope="prototype"></bean>
</beans>
Bean的生命周期
- bean对象创建(调用无参构造器)
- 给bean对象设置属性
- bean的后置处理器(初始化之前)
- bean对象的初始化(需在配置bean时指定初始化方法)
- bean的后置处理器(初始化之后)
- bean对象就绪可以使用
- bean对象销毁(需在配置bean时指定销毁方法)
- IoC容器关闭
package com.atguigu.spring6.iocxml.life;
public class User {
//无参数构造
public User() {
System.out.println("1 bean对象创建,调用无参数构造");
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("2 给bean对象设置属性值");
this.name = name;
}
//初始化的方法
public void initMethod() {
System.out.println("4 bean对象初始化,调用指定的初始化的方法");
}
//销毁的方法
public void destroyMethod() {
System.out.println("7 bean对象销毁,调用指定的销毁的方法");
}
}
package com.atguigu.spring6.iocxml.life;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("3 bean后置处理器,初始化之前执行");
System.out.println(beanName+"::"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("5 bean后置处理器,初始化之后执行");
System.out.println(beanName+"::"+bean);
return bean;
}
}
<?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="user" class="com.atguigu.spring6.iocxml.life.User"
scope="singleton" init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="lucy"></property>
</bean>
<!-- bean的后置处理器要放入IOC容器才能生效 -->
<bean id="myBeanPost" class="com.atguigu.spring6.iocxml.life.MyBeanPost"/>
</beans>
package com.atguigu.spring6.iocxml.life;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean-life.xml");
User user = context.getBean("user", User.class);
System.out.println("6 bean对象创建完成了,可以使用了");
System.out.println(user);
context.close(); //销毁
}
}
FactoryBean
FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。
package com.atguigu.spring6.iocxml.factorybean;
public class User {
}
package com.atguigu.spring6.iocxml.factorybean;
import org.springframework.beans.factory.FactoryBean;
public class MyFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
<?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="user" class="com.atguigu.spring6.iocxml.factorybean.MyFactoryBean"></bean>
</beans>
package com.atguigu.spring6.iocxml.factorybean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-factorybean.xml");
User user = (User) context.getBean("user");
System.out.println(user);
}
}
Spring基于Xml自动装配
自动装配:根据指定的策略,在IoC容器中某一个bean,自动为指定的Bean中依赖的类或接口中的属性赋值
在没有使用自动装配前:
package com.atguigu.spring6.iocxml.auto.dao;
public interface UserDao {
public void addUserDao();
}
package com.atguigu.spring6.iocxml.auto.dao;
public class UserDaoImpl implements UserDao{
@Override
public void addUserDao() {
System.out.println("userDao方法执行了...");
}
}
package com.atguigu.spring6.iocxml.auto.service;
public interface UserService {
public void addUserService();
}
package com.atguigu.spring6.iocxml.auto.service;
import com.atguigu.spring6.iocxml.auto.dao.UserDao;
import com.atguigu.spring6.iocxml.auto.dao.UserDaoImpl;
public class UserServiceImpl implements UserService{
@Override
public void addUserService() {
System.out.println("userService方法执行了...");
userDao.addUserDao();
UserDao userDao = new UserDaoImpl();
userDao.addUserDao();
}
}
package com.atguigu.spring6.iocxml.auto.controller;
import com.atguigu.spring6.iocxml.auto.service.UserService;
import com.atguigu.spring6.iocxml.auto.service.UserServiceImpl;
public class UserController {
public void addUser() {
System.out.println("controller方法执行了...");
//调用service的方法
userService.addUserService();
UserService userService = new UserServiceImpl();
userService.addUserService();
}
}
使用自动装配:
1.在controller里面设置service类型的属性,生成service属性set方法;在service里面设置dao类型的属性,生成dao属性set方法;
package com.atguigu.spring6.iocxml.auto.service;
import com.atguigu.spring6.iocxml.auto.dao.UserDao;
import com.atguigu.spring6.iocxml.auto.dao.UserDaoImpl;
public class UserServiceImpl implements UserService{
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUserService() {
System.out.println("userService方法执行了...");
userDao.addUserDao();
}
}
package com.atguigu.spring6.iocxml.auto.controller;
import com.atguigu.spring6.iocxml.auto.service.UserService;
import com.atguigu.spring6.iocxml.auto.service.UserServiceImpl;
public class UserController {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void addUser() {
System.out.println("controller方法执行了...");
//调用service的方法
userService.addUserService();
}
}
2. 编写配置文件
a)根据类型自动装配
<?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="userController" class="com.atguigu.spring6.iocxml.auto.controller.UserController"
autowire="byType">
</bean>
<bean id="userService" class="com.atguigu.spring6.iocxml.auto.service.UserServiceImpl"
autowire="byType">
</bean>
<bean id="userDao" class="com.atguigu.spring6.iocxml.auto.dao.UserDaoImpl">
</bean>
</beans>
package com.atguigu.spring6.iocxml.auto;
import com.atguigu.spring6.iocxml.auto.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean-auto.xml");
UserController controller = context.getBean("userController", UserController.class);
controller.addUser();
}
}
注意 :若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null。若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionException
b)根据名称自动装配:
<?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="userController" class="com.atguigu.spring6.iocxml.auto.controller.UserController"
autowire="byName">
</bean>
<bean id="userService" class="com.atguigu.spring6.iocxml.auto.service.UserServiceImpl"
autowire="byName">
</bean>
<bean id="userDao" class="com.atguigu.spring6.iocxml.auto.dao.UserDaoImpl">
</bean>
</beans>
基于注解实现自动装配
Spring 从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--开启组件扫描-->
<context:component-scan base-package="com.atguigu.spring6"></context:component-scan>
</beans>
- 使用注解定义 Bean
package com.atguigu.spring6.bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@Controller
public class User {
}
- 依赖注入