容器:IOC
控制反转(Ioc)
IoC容器在Spring的实现
Spring 的 IoC 容器就是 IoC思想的一个落地的产品实现。IoC容器中管理的组件也叫做 bean。在创建 bean 之前,首先需要创建IoC 容器。Spring 提供了IoC 容器的两种实现方式:
**①BeanFactory**
这是 IoC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用。
**②ApplicationContext**
BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用 ApplicationContext 而不是底层的 BeanFactory。
**③ApplicationContext的主要实现类**
获取bean的三种方式:
package com.zzq.spring6.iocxml;
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.xml");
//根据id获取bean
User user1=(User) context.getBean("user1");
System.out.println(""+user1);
//根据类型获取bean
User user2=context.getBean(User.class);
System.out.println(""+user2);
//根据id和类型获取bean
User user3=context.getBean("user",User.class);
System.out.println(""+user3);
}
}
如果组件类实现了接口,根据接口类型可以获取 bean 吗?
> 可以,前提是bean唯一
如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?
> 不行,因为bean不唯一
依赖注入:
1、类有属性,创建对象过程中,向属性设置值
第一种方式:基于set方法完成
package com.zzq.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);
}
}
book.java
package com.zzq.spring6.iocxml.di;
public class Book {
private String bname;
private String author;
@Override
public String toString() {
return "Book{" +
"bname='" + bname + '\'' +
", author='" + author + '\'' +
'}';
}
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Book(String bname, String author) {
this.bname = bname;
this.author = author;
}
public Book() {
}
}
bean-di.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="book" class="com.zzq.spring6.iocxml.di.Book">
<property name="author" value="后端"></property>
<property name="bname" value="java"></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">
<!--1、set方法注入-->
<bean id="book" class="com.zzq.spring6.iocxml.di.Book">
<property name="author" value="后端"></property>
<property name="bname" value="java"></property>
</bean>
<!-- 2、构造器注入-->
<bean id="bookCon" class="com.zzq.spring6.iocxml.di.Book">
<constructor-arg name="author" value="java开发"></constructor-arg>
<constructor-arg name="bname" value="spring"></constructor-arg>
</bean>
</beans>
package com.zzq.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);
}
}
特殊值处理
##### ①字面量赋值
> 什么是字面量?
>
> int a = 10;
>
> 声明一个变量a,初始化为10,此时a就不代表字母a了,而是作为一个变量的名字。当我们引用a的时候,我们实际上拿到的值是10。
>
> 而如果a是带引号的:'a',那么它现在不是一个变量,它就是代表a这个字母本身,这就是字面量。所以字面量没有引申含义,就是我们看到的这个数据本身。
```xml
<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>
```
##### ②null值
```xml
<property name="name">
<null />
</property>
```
> 注意:
>
> ```xml
> <property name="name" value="null"></property>
> ```
>
> 以上写法,为name所赋的值是字符串null
##### ③xml实体
```xml
<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 解决方案一:使用XML实体来代替 -->
<property name="expression" value="a < b"/>
```
##### ④CDATA节
```xml
<property name="expression">
<!-- 解决方案二:使用CDATA节 -->
<!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
<!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
<!-- 所以CDATA节中写什么符号都随意 -->
<value><![CDATA[a < b]]></value>
</property>
```
为对象类型属性赋值:
第一种方式:
引入外部bean
1、创建两个类对象:dept和emp
2、在emp的bean标签里面,使用property引入dept的bean
package com.zzq.spring6.iocxml.ditest;
//部门类
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
public void info(){
System.out.println("部门名称:"+dname);
}
}
package com.zzq.spring6.iocxml.ditest;
//员工类
public class Emp {
//对象类型属性:员工属于某个部门
private Dept dept;
private String ename;
private Integer age;
public Dept getDept() {
return dept;
}
public void work(){
System.out.println(ename+"emp work...."+age);
dept.info();
}
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;
}
}
package com.zzq.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-ditest.xml");
Emp emp = context.getBean("emp", Emp.class);
emp.work();
}
}
<?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.zzq.spring6.iocxml.ditest.Dept">
<property name="dname" value="维和部"></property>
</bean>
<bean id="emp" class="com.zzq.spring6.iocxml.ditest.Emp">
<!--普通属性注入-->
<property name="age" value="23"></property>
<property name="ename" value="aa"></property>
<!-- 注入对象类型属性-->
<property name="dept" ref="dept"></property>
</bean>
</beans>
第二种方式:
内部bean的注入
<!-- 内部bean注入-->
<bean id="emp2" class="com.zzq.spring6.iocxml.ditest.Emp">
<!--普通属性注入-->
<property name="age" value="2344"></property>
<property name="ename" value="aabbb"></property>
<!-- 注入对象类型属性-->
<property name="dept" >
<bean id="dept2" class="com.zzq.spring6.iocxml.ditest.Dept">
<property name="dname" value="维和部111"></property>
</bean>
</property>
</bean>
第三种方式:
级联赋值
<!-- 第三种方式 级联赋值-->
<bean id="dept3" class="com.zzq.spring6.iocxml.ditest.Dept">
<property name="dname" value="技术研发部"></property>
</bean>
<bean id="emp3" class="com.zzq.spring6.iocxml.ditest.Emp">
<property name="ename" value="Tom"></property>
<property name="age" value="22"></property>
<property name="dept" ref="dept3"></property>
<property name="dept.dname" value="测试部"></property>
</bean>
注入数组类型的属性
package com.zzq.spring6.iocxml.ditest;
import java.lang.reflect.Array;
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 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.zzq.spring6.iocxml.ditest.Dept">
<property name="dname" value="维和部"></property>
</bean>
<bean id="emp" class="com.zzq.spring6.iocxml.ditest.Emp">
<!--普通属性注入-->
<property name="age" value="23"></property>
<property name="ename" value="aa"></property>
<!-- 注入对象类型属性-->
<property name="dept" ref="dept"></property>
<!-- 数组类型属性-->
<property name="loves">
<array>
<value>睡觉</value>
<value>听歌</value>
<value>追剧</value>
</array>
</property>
</bean>
</beans>
为集合类型属性赋值
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="empone" class="com.zzq.spring6.iocxml.ditest.Emp">
<!--普通属性注入-->
<property name="age" value="23"></property>
<property name="ename" value="aa"></property>
</bean>
<bean id="emptwo" class="com.zzq.spring6.iocxml.ditest.Emp">
<!--普通属性注入-->
<property name="age" value="33"></property>
<property name="ename" value="agga"></property>
</bean>
<bean id="dept" class="com.zzq.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.zzq.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("dept", Dept.class);
dept.info();
}
}
package com.zzq.spring6.iocxml.ditest;
import java.util.List;
//部门类
public class Dept {
//一个部门有很多员工
private List<Emp> empList;
public List<Emp> getEmpList() {
return empList;
}
public void setEmpList(List<Emp> empList) {
this.empList = empList;
}
public String getDname() {
return dname;
}
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
public void info(){
System.out.println("部门名称:"+dname);
for (Emp emp:empList) {
System.out.println(emp.getEname());
}
}
}
map集合属性的注入
Student类
package com.zzq.spring6.iocxml.dimap;
import java.util.Map;
public class Student {
private String sid;
private String name;
private Map<String, Teacher> teacherMap;
public void run() {
System.out.println("学生编号: " + sid +
"学生名称: " + name);
System.out.println(teacherMap);
}
@Override
public String toString() {
return "Student{" +
"sid='" + sid + '\'' +
", name='" + name + '\'' +
", teacherMap=" + 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 getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Teacher类
package com.zzq.spring6.iocxml.dimap;
public class Teacher {
private String teacherId;
private String teacherName;
@Override
public String toString() {
return "Teacher{" +
"teacherId='" + teacherId + '\'' +
", teacherName='" + 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;
}
}
package com.zzq.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();
}
}
<?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="student" class="com.zzq.spring6.iocxml.dimap.Student">
<property name="name" value="aa"></property>
<property name="sid" value="111"></property>
<property name="teacherMap">
<map>
<entry>
<key>
<value>10001</value>
</key>
<ref bean="teacherone"></ref>
</entry>
<entry>
<key>
<value>10099</value>
</key>
<ref bean="teachertwo"></ref>
</entry>
</map>
</property>
</bean>
<bean id="teacherone" class="com.zzq.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="22"></property>
<property name="teacherName" value="王五"></property>
</bean>
<bean id="teachertwo" class="com.zzq.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="22"></property>
<property name="teacherName" value="王五"></property>
</bean>
</beans>
引入集合类型的bean
1、创建三个对象
2、注入普通类型属性
3、使用util:类型 定义
4、在学生bean引入util:类型定义bean,完成list、map类型属性注入
lesson
package com.zzq.spring6.iocxml.dimap;
public class Lesson {
private String lessonName;
@Override
public String toString() {
return "Lesson{" +
"lessonName='" + lessonName + '\'' +
'}';
}
public String getLessonName() {
return lessonName;
}
public void setLessonName(String lessonName) {
this.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">
<bean id="student" class="com.zzq.spring6.iocxml.dimap.Student">
<property name="name" value="lucy"></property>
<property name="sid" value="111"></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>10001</value>
</key>
<ref bean="teacherone"></ref>
</entry>
<entry>
<key>
<value>1208</value>
</key>
<ref bean="teachertwo"></ref>
</entry>
</util:map>
<bean id="lessonone" class="com.zzq.spring6.iocxml.dimap.Lesson">
<property name="lessonName" value="java开发"></property>
</bean>
<bean id="lessontwo" class="com.zzq.spring6.iocxml.dimap.Lesson">
<property name="lessonName" value="前端开发"></property>
</bean>
<bean id="teacherone" class="com.zzq.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="2201"></property>
<property name="teacherName" value="王五"></property>
</bean>
<bean id="teachertwo" class="com.zzq.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="2200"></property>
<property name="teacherName" value="刘五"></property>
</bean>
</beans>
引入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.zzq.spring6.iocxml.dimap.Student"
p:sid="111" p:name="流水" p:lessonList-ref="lessonList" p:teacherMap-ref="teacherMap">
</bean>
<bean id="student" class="com.zzq.spring6.iocxml.dimap.Student">
<property name="name" value="lucy"></property>
<property name="sid" value="111"></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>10001</value>
</key>
<ref bean="teacherone"></ref>
</entry>
<entry>
<key>
<value>1208</value>
</key>
<ref bean="teachertwo"></ref>
</entry>
</util:map>
<bean id="lessonone" class="com.zzq.spring6.iocxml.dimap.Lesson">
<property name="lessonName" value="java开发"></property>
</bean>
<bean id="lessontwo" class="com.zzq.spring6.iocxml.dimap.Lesson">
<property name="lessonName" value="前端开发"></property>
</bean>
<bean id="teacherone" class="com.zzq.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="2201"></property>
<property name="teacherName" value="王五"></property>
</bean>
<bean id="teachertwo" class="com.zzq.spring6.iocxml.dimap.Teacher">
<property name="teacherId" value="2200"></property>
<property name="teacherName" value="刘五"></property>
</bean>
</beans>
package com.zzq.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();
}
}
引入外部属性文件
引入依赖
<!-- 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>
创建外部属性文件
jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/spring?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
配置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"
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:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 完成数据库信息的注入-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClassName" value="${jdbc.driver}"></property>
</bean>
</beans>
测试
package com.zzq.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 demo1() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/spring?serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
}
@Test
public void demo2(){
ApplicationContext context=new
ClassPathXmlApplicationContext("bean-jdbc.xml");
DruidDataSource dataSource = context.getBean(DruidDataSource.class);
System.out.println(dataSource.getUrl());
}
}
bean的作用域
bean的生命周期
package com.zzq.spring6.iocxml.life;
public class User {
private String name;
//无参构造
public User() {
System.out.println("1 bean对象创建,调用无参构造");
}
//初始化方法
public void initMethod(){
System.out.println("4、bean对象初始化,调用指定的初始化方法");
}
//销毁的方法
public void destroyMethod(){
System.out.println("7、bean对象销毁,调用指定的销毁方法");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("2 给bean对象设置属性值");
this.name = name;
}
}
package com.zzq.spring6.iocxml.life;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;
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;
}
}
package com.zzq.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();//销毁对象
}
}
<?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.zzq.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.zzq.spring6.iocxml.life.MyBeanPost"></bean>
</beans>
FactoryBean
FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。
将来我们整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。
package com.zzq.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;
}
}
package com.zzq.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);
}
}
package com.zzq.spring6.iocxml.factorybean;
public class User {
}
<?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.zzq.spring6.iocxml.factorybean.MyFactoryBean"></bean>
</beans>
基于xml自动装配
package com.zzq.spring6.iocxml.auto.controller;
import com.zzq.spring6.iocxml.auto.service.UserService;
import com.zzq.spring6.iocxml.auto.service.UserSeviceImpl;
public class UserController {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void addUser(){
System.out.println("controller方法执行了");
//调用service的方法
userService.addUserService();
// UserService userService=new UserSeviceImpl();
// userService.addUserService();
}
}
package com.zzq.spring6.iocxml.auto.service;
public interface UserService {
public void addUserService();
}
package com.zzq.spring6.iocxml.auto.service;
import com.zzq.spring6.iocxml.auto.dao.UserDao;
import com.zzq.spring6.iocxml.auto.dao.UserDaoImpl;
public class UserSeviceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUserService() {
System.out.println("userService方法执行了");
userDao.addUserDao();
// UserDao userDao=new UserDaoImpl();
// userDao.addUserDao();
}
}
package com.zzq.spring6.iocxml.auto.dao;
public class UserDaoImpl implements UserDao {
@Override
public void addUserDao(){
System.out.println("userDao方法执行了");
}
}
package com.zzq.spring6.iocxml.auto.dao;
import com.zzq.spring6.iocxml.auto.service.UserService;
public interface UserDao {
public void addUserDao();
}
package com.zzq.spring6.iocxml.auto;
import com.zzq.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();
}
}
<?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.zzq.spring6.iocxml.auto.controller.UserController" autowire="byType"></bean>-->
<!--<bean id="userService" class="com.zzq.spring6.iocxml.auto.service.UserSeviceImpl" autowire="byType"></bean>-->
<!--<bean id="userDao" class="com.zzq.spring6.iocxml.auto.dao.UserDaoImpl"></bean>-->
<!-- 根据名称自动装配-->
<bean id="userController" class="com.zzq.spring6.iocxml.auto.controller.UserController" autowire="byName"></bean>
<bean id="userService" class="com.zzq.spring6.iocxml.auto.service.UserSeviceImpl" autowire="byName"></bean>
<bean id="userDao" class="com.zzq.spring6.iocxml.auto.dao.UserDaoImpl"></bean>
</beans>
自动装配方式:byName
>
> byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值
基于注解管理Bean
开启组件扫描
<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.zzq"></context:component-scan>
</beans>
情况一:最基本的扫描方式**
```xml
<context:component-scan base-package="com.atguigu.spring6">
</context:component-scan>
```
**情况二:指定要排除的组件**
```xml
<context:component-scan base-package="com.atguigu.spring6">
<!-- context:exclude-filter标签:指定排除规则 -->
<!--
type:设置排除或包含的依据
type="annotation",根据注解排除,expression中设置要排除的注解的全类名
type="assignable",根据类型排除,expression中设置要排除的类型的全类名
-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!--<context:exclude-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>
```
**情况三:仅扫描指定组件**
```xml
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
<!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
<!-- 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类 -->
<!--
type:设置排除或包含的依据
type="annotation",根据注解排除,expression中设置要排除的注解的全类名
type="assignable",根据类型排除,expression中设置要排除的类型的全类名
-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<!--<context:include-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>
```
bean对象的创建
以上四个注解都可实现bean的创建
package com.zzq.bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
@Component(value = "user")//<bean id="user" class="...">属性可不写,默认为user
//@Controller
//@Repository
//@Service
public class User {
}
属性注入
单独使用@Autowired注解,**默认根据类型装配**。【默认是byType】
package com.zzq.autowired.controller;
import com.zzq.autowired.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
//注入service
//第一种方式属性的注入
@Autowired//根据类型找到对应对象,完成注入
private UserService userService;
public void add(){
System.out.println("controller...");
userService.add();
}
}
package com.zzq.autowired.service;
import com.zzq.autowired.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService{
//注入dao
//第一种方式属性注入
//@Autowired
// private UserDao userDao;
//第二种方式set方法注入
// @Autowired
// private UserDao userDao;
//
// public void setUserDao(UserDao userDao) {
// this.userDao = userDao;
// }
//第三种方式:构造方法中注入
private UserDao userDao;
@Autowired
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void add() {
System.out.println("service...");
userDao.add();
}
}
package com.zzq.autowired.controller;
import com.zzq.autowired.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
//注入service
//第一种方式属性的注入
// @Autowired//根据类型找到对应对象,完成注入
// private UserService userService;
//第二种方式set方法注入
// private UserService userService;
//@Autowired
// public void setUserService(UserService userService) {
// this.userService = userService;
// }
//第三种方式 构造方法的注入
// private UserService userService;
//@Autowired
// public UserController(UserService userService) {
// this.userService = userService;
// }
//第四种方式
private UserService userService;
public UserController( @Autowired UserService userService) {
this.userService = userService;
}
public void add(){
System.out.println("controller...");
userService.add();
}
}
@Autowired注解可以出现在:属性上、构造方法上、构造方法的参数上、setter方法上。
- 当带参数的构造方法只有一个,@Autowired注解可以省略。()
- @Autowired注解默认根据类型注入。如果要根据名称注入的话,需要配合@Qualifier注解一起使用。
@Resource注入
@Resource注解也可以完成属性注入。那它和@Autowired注解有什么区别?
- @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
- @Autowired注解是Spring框架自己的。
- **@Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。**
- **@Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。**
- @Resource注解用在属性上、setter方法上。
- @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。
@Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖:【**如果是JDK8的话不需要额外引入依赖。高于JDK11或低于JDK8需要引入以下依赖。**】
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
package com.zzq.resource.controller;
import com.zzq.resource.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller("myUserController")
public class UserController {
//根据名称进行注入
//@Resource(name = "myUserService")
//private UserService userService;
//根据类型进行注入
@Resource
private UserService userService;
public void add(){
System.out.println("controller...");
userService.add();
}
}
Spring全注解开发
package com.zzq.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration//配置类
@ComponentScan("com.zzq")//开启组件扫描
public class SpringConfig {
}
package com.zzq.resource;
import com.zzq.config.SpringConfig;
import com.zzq.resource.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUserControllerAnno {
public static void main(String[] args) {
//加载配置类
ApplicationContext context=
new AnnotationConfigApplicationContext(SpringConfig.class);
UserController controller = context.getBean(UserController.class);
controller.add();
}
}
java反射机制
package com.zzq;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestCar {
//1、获取clas对象多种方式
@Test
public void test01() throws Exception {
//1、类名.class
Class clazz1 = Car.class;
//2、对象.getclass()
Class clazz2 = new Car().getClass();
//3、Class.forname("全路径")
Class clazz3 = Class.forName("com.zzq.Car");
//实例化
Car car = (Car) clazz3.getDeclaredConstructor().newInstance();
System.out.println(car);
}
//2、通过反射获取构造方法
@Test
public void test02() throws Exception {
Class clazz = Car.class;
//获取所有构造
Constructor[] constructors = clazz.getConstructors();
for (Constructor c : constructors) {
System.out.println("方法个数" + c.getName() + "参数个数" + c.getParameterCount());
}
//指定有参数构造创建对象
//1、构造public
// Constructor c1=clazz.getConstructor(String.class,int.class, String.class);
// Car car1 = (Car)c1.newInstance("本部", 10, "黄色");
// System.out.println(car1);
//2、构造private
Constructor c2 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
c2.setAccessible(true);
Car car2 = (Car) c2.newInstance("部", 11, "黄色");
System.out.println(car2);
}
//3、获取属性
@Test
public void test03() throws Exception {
Class clazz = Car.class;
//实例化
Car car = (Car) clazz.getDeclaredConstructor().newInstance();
//获取所有的public属性
// Field[]fields=clazz.getFields();
//获取所有属性(包含私有属性)
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals("name")) {
field.setAccessible(true);
field.set(car, "奥迪");
}
System.out.println(field.getName());
System.out.println(car);
}
}
//4、获取方法
@Test
public void test04() throws Exception {
Car car=new Car("宝马",19,"黑色");
Class clazz=car.getClass();
//public方法
Method[]methods=clazz.getMethods();
for (Method m1:methods
) {
// System.out.println(m1.getName());
//执行方法toString
if (m1.getName().equals("toString")){
String invoke=(String) m1.invoke(car);
// System.out.println("toString执行了:"+invoke);
}
//private方法
Method[] methodsAll = clazz.getDeclaredMethods();
for (Method m:methodsAll){
if (m.getName().equals("run")){
m.setAccessible(true);
m.invoke(car);
}
}
}
}
}
实现Spring的IoC
ApplicationContext.java
package com.zzq.Bean;
import com.zzq.anno.Bean;
public interface ApplicationContext {
Object getBean(Class clazz);
}
AnnotationApplicationContext.java
package com.zzq.Bean;
import com.zzq.anno.Bean;
import com.zzq.anno.Di;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class AnnotationApplicationContext implements ApplicationContext {
//创建map集合,放bean对象
private Map<Class, Object> beanFactory = new HashMap<>();
private static String rootPath;
//返回对象
@Override
public Object getBean(Class clazz) {
return beanFactory.get(clazz);
}
//设置包扫描规则
//当前包及其子包,拿个类有@Bean注解,把这个类通过反射实例化
public AnnotationApplicationContext(String basePackage) {
// public static void pathdemo1(String basePackage) {
//把.替换成\
try {
String packagePath = basePackage.replaceAll("\\.", "\\\\");
//获取包绝对路径
Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
String filePath = URLDecoder.decode(url.getFile(), "utf-8");
//获取包前面路径得到部分,字符串截取
rootPath = filePath.substring(0, filePath.length() - packagePath.length());
//包扫描
loadBean(new File(filePath));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
//属性得到注入
loadDi();
}
// //包扫描的过程,实例化
private void loadBean(File file) throws Exception {
//1、判断当前是否文件夹
if (file.isDirectory()) {
//2、获取文件夹里面所有内容
File[] childrenFiles = file.listFiles();
//3、判断文件夹里面为空,直接返回
if (childrenFiles == null || childrenFiles.length == 0) {
return;
}
//4、如果文件夹里面不为空,遍历文件夹所有内容
for (File child : childrenFiles) {
//4.1遍历得到某个File对象,继续判断,如果还是文件,
if (child.isDirectory()) {
//递归
loadBean(child);
} else {
//4.2遍历得到File对象不是文件夹,是文件
//4.3得到包路径+类名称部分-字符串截取
String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
//4.4判断当前文件类型是否.class
if (pathWithClass.contains(".class")) {
//4.5如果是.class类型,把路径\替换. 把class去掉
String allName = pathWithClass.replaceAll("\\\\", ".")
.replace(".class", "");
//4.6判断类上面是否有注解@Bean,如果有实例化过程
//4.6.1获取类发class
Class<?> clazz = Class.forName(allName);
//4.6.2判断不是接口
if (!clazz.isInterface()) {
//4.6.3判断类上面是否有注解@Bean
Bean annotation = clazz.getAnnotation(Bean.class);
if ((annotation != null)) {
//4.6.4实例化
Object instance = clazz.getConstructor().newInstance();
//4.7把对象实例化之后,放到map集合beanFactory
//4.7.1判断当前类如果有接口,让接口class作为map的key
if (clazz.getInterfaces().length > 0) {
beanFactory.put(clazz.getInterfaces()[0], instance);
} else {
beanFactory.put(clazz, instance);
}
}
}
}
}
}
}
}
//属性注入
private void loadDi() {
//实例化对象在beanFactory的map集合里面
//1、遍历beanFactory的map集合
Set<Map.Entry<Class,Object>>entries=beanFactory.entrySet();
for (Map.Entry<Class,Object>entry:entries) {
//2、获取map集合每个对象(value),每个对象属性获取到
Object obj=entry.getValue();
//获取对象Class
Class<?> clazz=obj.getClass();
//获取每个对象的属性
Field[] declaredFields = clazz.getDeclaredFields();
//遍历得到每个对象属性数组,得到每个属性
for (Field field:declaredFields) {
//4、判断属性上面是否有@Di注解
Di annotation = field.getAnnotation(Di.class);
if (annotation != null) {
//如果私有属性,设置可以设置值
field.setAccessible(true);
//5、如果有@Di注解,把对象进行设置(注入)
try {
field.set(obj, beanFactory.get(field.getType()));
}catch (IllegalAccessException e){
throw new RuntimeException(e);
}
}
}
}
}
}
package com.zzq.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}
package com.zzq.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Di {
}
package com.zzq;
import com.zzq.Bean.AnnotationApplicationContext;
import com.zzq.Bean.ApplicationContext;
import com.zzq.service.UserService;
public class TestUser {
public static void main(String[] args) {
ApplicationContext context=
new AnnotationApplicationContext("com.zzq");
UserService userService = (UserService)context.getBean(UserService.class);
System.out.println(userService);
userService.add();
}
}