Spring 框架的几个核心概念:
IoC: Inversion of Control:控制反转
DI: Dependency Injection:依赖注入
AOP: Aspect Oriented Programming:面向切面编程
Object Oriented Programming: 面向对象编程
这里使用的 Spring 的版本是:5.2.8.release
耦合:我依赖你,你不见了(不要你了),对我影响很大,我就得改代码
写代码的方向:解耦,降低耦合性
① 通过类加载器读取配置文件的输入流
② 通过 Properties
对象的 load()
方法,传入输入流【加载配置文件】
③ 通过 Properties
对象的 getProperty(String key)
方法获取到 key 对应的 value 值
④ 使用反射 API,通过全类名创建类的实例
/**
* 创建对象实例的工厂
*/
public class InstanceFactory {
// Properties 对象表示【.properties】配置文件
private static Properties properties;
static {
// 获取配置文件的输入流
try (InputStream is = InstanceFactory.class.getClassLoader().getResourceAsStream("properties.properties")) {
properties = new Properties();
// 加载配置文件输入流
properties.load(is);
} catch (Exception e) {
e.printStackTrace();
}
}
private static ObjectAble getObjectByName(String key) {
// 获取配置文件内容
String fullPath = properties.getProperty(key);
try {
Class<?> cls = Class.forName(fullPath);
return (ObjectAble) cls.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static ObjectAble create(String key) {
return getObjectByName(key);
}
}
properties.properties 配置文件
personFullPath=com.guoqing.po.PersonV2
dogFullPath=com.guoqing.po.DogV2
boyFullPath=com.guoqing.po.Boy
工厂模式结合配置文件降低类之间的耦合
Spring 的 IoC 就是一个大工厂
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.8.RELEASEversion>
dependency>
<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="boy" class="com.guoqing.po.Boy" />
<bean id="personV1" class="com.guoqing.po.PersonV1" />
<bean id="personV2" class="com.guoqing.po.PersonV2" />
beans>
类路径的东西:
① java 文件夹中的东西(打包后classes
中的内容)
② resources 文件夹中的东西
public class QQMain {
public static void main(String[] args) {
// 读取 Spring 的核心配置文件, 并得到 Spring 的 IoC 工厂
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 通过 IoC 工厂获取实例(boy 是 Spring 的核心配置文件中的 bean 标签的 id 属性配置的内容)
Boy boy = ctx.getBean("boy", Boy.class);
System.out.println("boy = " + boy);
}
}
读取配置文件,并返回 IoC 容器的类是:ClassPathXmlApplicationContext
调用 ClassPathXmlApplicationContext 对象的getBean()
方法,传入 bean 标签的 id 值 获取对象实例
属性的本质含义是:
set 方法
后面的值改为小写
①setName()
【name 就是属性】
②setBoySchool()
【boySchool 就是属性】
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
通过
logback-classic
框架可以看到 Spring 相关的日志信息
<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="bookDaoImpl" class="com.guoqing.dao.impl.BookDaoImpl"/>
<bean id="bookServiceImpl" class="com.guoqing.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDaoImpl"/>
bean>
<bean id="bookController" class="com.guoqing.controller.BookController">
<property name="bookService" ref="bookServiceImpl"/>
bean>
beans>
常见的注入类型有3大类:
① bean(自定义类型)【ref 属性
】
② 基本类型、String、BigDecimal、包装类型【value
属性】
③ 集合类型(数组、Map、List、Set、Properties)☆
常见的注入方式有 2 种:
① 基于 setter(属性)
② 基于 constructor (构造方法)
<bean id="cat" class="com.guoqing.domain.Cat">
<property name="catName" value="哆啦A梦"/>
<property name="color" value="BLUE"/>
bean>
<bean id="person" class="com.guoqing.domain.Person">
<property name="cat" ref="cat"/>
bean>
<bean id="cat" class="com.guoqing.domain.Cat">
<property name="catName" value="哆啦A梦"/>
<property name="color" value="BLUE"/>
bean>
<bean id="person" class="com.guoqing.domain.Person">
<property name="cat">
<ref bean="cat"/>
property>
bean>
<bean id="girl" class="com.guoqing.domain.Girl">
<property name="cat">
<bean class="com.guoqing.domain.Cat">
<property name="catName" value="卡菲"/>
<property name="color" value="PINK"/>
bean>
property>
bean>
<bean id="person" class="com.guoqing.domain.Person">
<property name="id" value="666"/>
<property name="name">
<value>张国庆value>
property>
<property name="age" value="8"/>
<property name="money">
<value>88888.666value>
property>
bean>
<bean id="whatever" class="com.guoqing.domain.Whatever">
<property name="books">
<array>
<value>Java 编程思想value>
<value>红楼梦value>
<value>水浒传value>
<value>三国演义value>
<value>三体value>
array>
property>
<property name="cats">
<array>
<bean class="com.guoqing.domain.Cat">
<property name="color" value="RED"/>
<property name="catName" value="小红"/>
bean>
<bean class="com.guoqing.domain.Cat">
<property name="color" value="BLACK"/>
<property name="catName" value="小黑"/>
bean>
array>
property>
bean>
<bean id="whatever" class="com.guoqing.domain.Whatever">
<property name="books">
<list>
<value>Thinking In Javavalue>
<value>红楼梦value>
<value>水浒传value>
<value>三国演义value>
<value>三体value>
list>
property>
<property name="cats">
<list>
<bean class="com.guoqing.domain.Cat">
<property name="color" value="RED"/>
<property name="catName" value="小红"/>
bean>
<bean class="com.guoqing.domain.Cat">
<property name="color" value="BLACK"/>
<property name="catName" value="小黑黑"/>
bean>
list>
property>
bean>
<bean id="whatever" class="com.guoqing.domain.Whatever">
<property name="goods">
<set>
<value>苹果1value>
<value>土豆2value>
<value>西瓜3value>
<value>电脑4value>
<value>窗户5value>
<value>窗户5value>
<value>窗户5value>
<value>鼠标6value>
set>
property>
bean>
HashSet 是无顺序的【可去重】
LinkedHashSet 是有顺序的【可去重】
<bean id="whatever" class="com.guoqing.domain.Whatever">
<property name="peoSal">
<map>
<entry key="张国庆" value="88888"/>
<entry key="周杰伦" value="155555"/>
<entry key="王凡" value="266666"/>
<entry key="陈铭酒" value="12121"/>
<entry key="刘德华" value="888888"/>
map>
property>
<property name="peoCatMap">
<map>
<entry key="ZGQ">
<bean class="com.guoqing.domain.Cat">
<property name="catName" value="猫猫1"/>
<property name="color" value="RED"/>
bean>
entry>
<entry key="CMJ">
<bean class="com.guoqing.domain.Cat">
<property name="catName" value="猫猫2"/>
<property name="color" value="PINK"/>
bean>
entry>
map>
property>
bean>
<bean id="whatever" class="com.guoqing.domain.Whatever">
<property name="properties">
<props>
<prop key="dao">com.guoqing.dao.impl.BookDaoImplprop>
<prop key="service">com.guoqing.service.impl.BookServiceImplprop>
props>
property>
bean>
基于 setter 注入调用的是无参的构造方法
没有命名空间的写法:
<bean id="cat" class="com.guoqing.domain.Cat">
<property name="color" value="skyblue"/>
<property name="catName" value="阿辉"/>
bean>
<bean id="teacher" class="com.guoqing.domain.Teacher">
<property name="id" value="2"/>
<property name="name" value="李老师"/>
<property name="salary" value="12121.666"/>
<property name="gender" value="男"/>
<property name="cat" ref="cat"/>
bean>
命名空间写法:
增加命名空间:
xmlns:p="http://www.springframework.org/schema/p"
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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="cat" class="com.guoqing.domain.Cat" p:catName="阿辉辉" p:color="SKYBLUE"/>
<bean id="teacher"
p:name="张国庆老师"
p:id="22"
p:salary="6666.666"
p:gender="男"
p:cat-ref="cat"
class="com.guoqing.domain.Teacher"/>
beans>
<bean id="student" class="com.guoqing.domain.Student"/>
<bean id="student" class="com.guoqing.domain.Student">
<constructor-arg value="张国庆"/>
bean>
<bean id="student" class="com.guoqing.domain.Student">
<constructor-arg value="张国庆"/>
<constructor-arg value="99.5"/>
bean>
<bean id="student" class="com.guoqing.domain.Student">
<constructor-arg value="99.5" type="double"/>
<constructor-arg value="张国庆" type="java.lang.String"/>
bean>
<bean id="student" class="com.guoqing.domain.Student">
<constructor-arg value="99.5" index="1"/>
<constructor-arg value="张国庆" index="0"/>
bean>
<bean id="student" class="com.guoqing.domain.Student">
<constructor-arg value="张国庆" index="0"/>
<constructor-arg>
<bean class="com.guoqing.domain.Cat">
<property name="catName" value="花儿"/>
<property name="color" value="ORANGE"/>
bean>
constructor-arg>
bean>
<bean id="cat" class="com.guoqing.domain.Cat">
<property name="catName" value="流浪猫"/>
<property name="color" value="GRAY"/>
bean>
<bean id="student" class="com.guoqing.domain.Student">
<constructor-arg value="张国庆" index="0"/>
<constructor-arg ref="cat"/>
bean>
<bean id="cat" class="com.guoqing.domain.Cat">
<property name="catName" value="流浪猫"/>
<property name="color" value="GRAY"/>
bean>
<bean id="student" class="com.guoqing.domain.Student">
<constructor-arg value="张国庆" index="0"/>
<constructor-arg>
<ref bean="cat"/>
constructor-arg>
bean>
<bean id="student" class="com.guoqing.domain.Student">
<constructor-arg type="java.util.List">
<list>
<value>语文value>
<value>数学value>
<value>英语value>
<value>物理value>
<value>化学value>
list>
constructor-arg>
bean>
Spring 的配置文件中配置的对象只需要执行某些构造方法即可创建
当遇到创建过程极其复杂的对象(无法通过调用构造方法创建的对象)时就需要下面的方式了
如:JDBC 的 Connection 对象的创建
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.19version>
dependency>
public class JdbcConnectionFactory {
/**
* 静态工厂
*/
public static Connection getConnection() throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection("jdbc:mysql://localhost:3306/jump_zgq?serverTimezone=UTC", "root", "root");
}
}
<bean id="jdbcConnection"
class="com.guoqing.factory.JdbcConnectionFactory"
factory-method="getConnection"/>
把创建复杂对象代码写在工厂中
通过该工厂中的 static 方法返回对象的实例
在 Spring 的核心配置文件中,通过factory-method
属性指定需要调用该工厂类的哪个方法返回对象实例
【缺点】无法传参
public class JdbcConnectionFactory {
private String driverClass;
private String url;
private String user;
private String pwd;
public JdbcConnectionFactory(String driverClass, String url, String user, String pwd) {
this.driverClass = driverClass;
this.url = url;
this.user = user;
this.pwd = pwd;
}
/**
* 实例工厂
*/
public Connection getConnection() throws Exception {
System.out.println("调用了 getConnection() 方法");
Class.forName(this.driverClass);
return DriverManager.getConnection(url, user, pwd);
}
}
<bean id="jdbcConnectionFactory" class="com.guoqing.factory.JdbcConnectionFactory">
<constructor-arg name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<constructor-arg name="url" value="jdbc:mysql://localhost:3306/jump_zgq?serverTimezone=UTC"/>
<constructor-arg name="user" value="root"/>
<constructor-arg name="pwd" value="root"/>
bean>
<bean id="jdbcConnection" factory-bean="jdbcConnectionFactory" factory-method="getConnection"/>
factory-bean
属性指代工厂类的实例
factory-method
属性指代要调用工厂对象的哪个实例方法来返回该复杂对象
Spring 提供的、用于方便地创建复杂对象的接口
本质和【实例工厂】类似
public class JdbcConnectionFactoryBean implements FactoryBean<Connection> {
private String driverClass;
private String url;
private String user;
private String pwd;
public JdbcConnectionFactoryBean(String driverClass, String url, String user, String pwd) {
this.driverClass = driverClass;
this.url = url;
this.user = user;
this.pwd = pwd;
}
/**
* 写创建该复杂对象的一系列代码
*/
@Override
public Connection getObject() throws Exception {
System.out.println("调用了 getObject() 方法");
Class.forName(this.driverClass);
return DriverManager.getConnection(url, user, pwd);
}
@Override
public Class<?> getObjectType() {
return Connection.class;
}
}
<bean id="jdbcConnection" class="com.guoqing.factoryBean.JdbcConnectionFactoryBean">
<constructor-arg name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<constructor-arg name="url" value="jdbc:mysql://localhost:3306/jump_zgq?serverTimezone=UTC"/>
<constructor-arg name="user" value="root"/>
<constructor-arg name="pwd" value="root"/>
bean>
监听
class
属性后的类是否实现(implements)了FactoryBean 接口
若实现了 FactoryBean 接口,则调用该类的getObject()
方法,然后将该方法返回的实例放入 IoC 容器中
若就是想拿到该类的实例,可通过
&
符号拼接上 id 属性的值,然后通过getBean()
方法获取
public class QQMain {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Object bean = ctx.getBean("&jdbcConnection");
// bean = com.guoqing.factoryBean.JdbcConnectionFactoryBean@436e852b
System.out.println("bean = " + bean);
}
}
若文章有错误请不吝赐教