⼀、Spring启示录
dao层:
UserDao接口:
//持久层
public interface UserDao {
//根据id删除用户信息
void deleteById();
}
UserDaoImplForMySQL实现类:
public class UserDaoImplForMySQL implements UserDao {
@Override
public void deleteById() {
System.out.println("Mysql数据库正在删除用户信息..........");
}
}
service层:
UserService接口:
//业务层
public interface UserService {
//删除用户信息
void deleteUser();
}
UserServiceImpl实现类:
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImplForMySQL();
@Override
public void deleteUser() {
//删除用户信息的逻辑
userDao.deleteById();
}
public void saveUser(){
userDao.deleteById();
}
}
web层:
UserAction类:
//表示层
public class UserAction {
private UserService userService = new UserServiceImpl();
//删除用户信息的请求
public void deleteRequest(){
userService.deleteUser();
}
}
client:
Test类:
public class Test {
public static void main(String[] args) {
UserAction userAction = new UserAction();
userAction.deleteRequest();
}
}
public class UserDaoImplForOracle implements UserDao {
@Override
public void deleteById() {
System.out.println("Oracle数据库正在删除用户数据..............");
}
}
而且还要修改UserSerciceImpl里面的对象
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImplForMySQL();
//private UserDao userDao = new UserDaoImplForOracle();
@Override
public void deleteUser() {
//删除用户信息的逻辑
userDao.deleteById();
}
public void saveUser(){
userDao.deleteById();
}
}
1.1 OCP开闭原则
1. OCP开闭原则 * 什么是OCP? OCP是软件七大开发原则当中最基本的一个原则:开闭原则 对什么开?对扩展开放。 对什么闭?对修改关闭。 * OCP原则是最核心的,最基本的,其他的六个原则都是为这个原则服务的。 * OCP开闭原则的核心是什么? 只要你在扩展系统功能的时候,没有修改以前写好的代码,那么你就是符合OCP原则的。 反之,如果在扩展系统功能的时候,你修改了之前的代码,那么这个设计是失败的,违背OCP原则。 * 当进行系统功能扩展的时候,如果动了之前稳定的程序,修改了之前的程序,之前所有程序都需要进行重新测试。这是不想看到的,因为非常麻烦。
1.2 依赖倒置原则DIP
2. 依赖倒置原则(DIP原则) * 什么是依赖倒置原则? 面向接口编程,面向抽象编程,不要面向具体编程。 * 依赖倒置原则的目的? 降低程序的耦合度,提高扩展力。 * 什么叫做符合依赖倒置? 上 不依赖 下,就是符合。 * 什么叫做违背依赖倒置? 上 依赖 下,就是违背。 只要“下”一改动,“上”就受到牵连。 3. 当前程序的设计,显然既违背OCP,又违背DIP,怎么办? 可以采用“控制反转”这种编程思想来解决这个问题。
public class UserServiceImpl implements UserService {
private UserDao userDao;
//private UserDao userDao = new UserDaoImplForOracle();
@Override
public void deleteUser() {
//删除用户信息的逻辑
userDao.deleteById();
}
public void saveUser(){
userDao.deleteById();
}
}
1.3 控制反转IoC
4. 什么是控制反转? 控制反转:IoC(Inversion of Control) 反转是什么呢? 反转的是两件事: 第一件事:我不在程序中采用硬编码的方式来new对象了。(new对象我不管了,new对象的权利交出去了。) 第二件事:我不在程序中采用硬编码的方式来维护对象的关系了。(对象之间关系的维护权,我也不管了,交出去了。) 控制反转:是一种编程思想。或者叫做一种新型的设计模式。由于出现的比较新,没有被纳入GoF23种设计模式范围内。
1.4 spring
5. Spring框架 * Spring框架实现了控制反转IoC这种思想 Spring框架可以帮你new对象。 Spring框架可以帮你维护对象和对象之间的关系。 * Spring是一个实现了IoC思想的容器。 * 控制反转的实现方式有多种,其中比较重要的叫做:依赖注入(Dependency Injection,简称DI)。 * 控制反转是思想。依赖注入是这种思想的具体实现。 * 依赖注入DI,又包括常见的两种方式: 第一种:set注入(执行set方法给属性赋值) 第二种:构造方法注入(执行构造方法给属性赋值) * 依赖注入 中 “依赖”是什么意思? “注入”是什么意思? 依赖:A对象和B对象的关系。 注入:是一种手段,通过这种手段,可以让A对象和B对象产生关系。 依赖注入:对象A和对象B之间的关系,靠注入的手段来维护。而注入包括:set注入和构造注入。 6. 注意术语: OCP:开闭原则(开发原则) DIP:依赖倒置原则(开发原则) IoC:控制反转(一种思想,一种新型的设计模式) DI:依赖注入(控制反转思想的具体实现方式)
⼆、Spring概述
2.1 Spring简介
2.2 Spring8⼤模块
2.3 Spring特点
三、Spring的⼊⻔程序
3.1 Spring的下载
<!--Spring6的正式版发布之前,这个仓库地址是需要的-->
<repositories>
<repository>
<id>repository.spring.milestone</id>
<name>Spring Milestone Repository</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<dependencies>
<!--spring context依赖:使⽤的是6.0.0-M2⾥程碑版-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.0-M2</version>
</dependency>
</dependencies>
3.2 第⼀个Spring程序
<packaging>jar</packaging>
<dependencies>
<!--spring context依赖-->
<!--当你引入Spring Context依赖以后,表示将Spring的基础依赖引入了-->
<!--如果,你想使用spring的jdbc,或者说其他的tx,那么还需要再次添加依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
//这是一个Bean,封装了用户的信息,Spring可以帮助我们创建User对象
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">
<!--这就是Spring的配置文件-->
<!--IDEA工具为我们提供了这个文件的模板,一定要使用这个模板来创建-->
<!--这个文件名不一定叫做spring.xml,可以是其它名字。-->
<!--这个文件最好是放在类路径当中,方便后期的移植。-->
<!--放在resources根目录下,就相当于是放到了类的根路径下。-->
<!--配置bean,这样spring才可以帮助我们管理这个对象。-->
<!--
bean标签的两个重要属性:
id:是这个bean的身份证号,不能重复,是唯一的标识。
class:必须填写类的全路径,全限定类名。(带包名的类名)
-->
<bean id="userBean" class="com.powernode.spring6.bean.User"/>
<!--配置其他bean-->
<bean id="userDaoBean" class="com.powernode.spring6.dao.UserDaoImplForMySQL"/>
</beans>
@Test
public void testFirstSpringCode() {
//第一步:获取Spring容器对象
//ApplicationContext 翻译为:应用上下文,其实就是Spring容器
// ApplicationContext 是一个接口。
// ApplicationContext 接口下有很多实现类。其中有一个实现类叫做:ClassPathXmlApplicationContext
// ClassPathXmlApplicationContext 专门从类路径当中加载spring配置文件的一个Spring上下文对象。
// 这行代码只要执行:就相当于启动了Spring容器,解析spring.xml文件,并且实例化所有的bean对象,放到spring容器当中。
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
//第二步:根据bean的id从Spring容器中获取这个对象,里面写bean的id
Object userBean = applicationContext.getBean("userBean");
System.out.println(userBean);//com.powernode.spring6.bean.User@294425a7
//获取其他bean
Object userDaoBean = applicationContext.getBean("userDaoBean");
System.out.println(userDaoBean);//com.powernode.spring6.dao.UserDaoImplForMySQL@67d48005
}
// dom4j解析beans.xml⽂件,从中获取class的全限定类名
// 通过反射机制调⽤⽆参数构造⽅法创建对象
Class clazz = Class.forName("com.powernode.spring6.bean.User");
Object obj = clazz.newInstance();
4. spring配置⽂件的名字是随意的
这个spring配置⽂件名字是我们负责提供的,显然spring配置⽂件的名字是随意的。
5. 像这样的beans.xml⽂件可以有多个
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml","beans.xml");
<!--配置java.util.Date Bean-->
<bean id="nowTime" class="java.util.Date"/>
//出现异常,不会返回null ,NoSuchBeanDefinitionException: No bean named 'nowTime22' available
Object nowTime = applicationContext.getBean("nowTime22");
System.out.println(nowTime);//Sat Aug 05 14:31:09 CST 2023
//NoSuchBeanDefinitionException: No bean named 'nowTime22' available
// Object nowTime = applicationContext.getBean("nowTime");
Date nowTime = (Date)applicationContext.getBean("nowTime");
//System.out.println(nowTime);//Sat Aug 05 14:31:09 CST 2023
//日期格式化 需要将object强转成Date类型,才能使用
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String format = sdf.format(nowTime);
System.out.println(format);//2023-08-05 14:37:14 542
使用getBean里面的参数:
//不想强制类型转换,指定第二个参数,直接返回我们需要的类型
Date nowTime1 = applicationContext.getBean("nowTime", Date.class);
System.out.println("nowTime1="+nowTime1);//nowTime1Sat= Aug 05 14:38:57 CST 2023
ApplicationContext urlSpring = new FileSystemXmlApplicationContext("d:/spring6.xml");
@Test
public void testBeanFactory(){
//ApplicationContext接口的超级父接口是:BeanFactory(翻译为Bean工厂,就是能够生产Bean对象的一个工厂对象。)
//BeanFactory是IoC容器的顶级接口。
//Spring的IoC容器底层实际上使用了:工厂模式。
//Spring底层的IoC是怎么实现的?XML解析 + 工厂模式 + 反射机制
//ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
BeanFactory applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
}
@Test
public void testBeginInitBean(){
// 注意:不是在调用getBean()方法的时候创建对象,执行以下代码的时候,就会实例化对象。
new ClassPathXmlApplicationContext("spring6.xml");
}
3.3 Spring6启⽤Log4j2⽇志框架
<!--log4j2的依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.20.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<loggers>
<!--
level指定⽇志级别,从低到⾼的优先级:
ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF
-->
<root level="DEBUG">
<appender-ref ref="spring6log"/>
</root>
</loggers>
<appenders>
<!--输出⽇志信息到控制台-->
<console name="spring6log" target="SYSTEM_OUT">
<!--控制⽇志输出的格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
</console>
</appenders>
</configuration>
@Test
public void testBeginInitBean() {
// 注意:不是在调用getBean()方法的时候创建对象,执行以下代码的时候,就会实例化对象。
new ClassPathXmlApplicationContext("spring6.xml");
// 你自己怎么去使用log4j2记录日志信息呢?
// 第一步:创建日志记录器对象
// 获取FirstSpringTest类的日志记录器对象,也就是说只要是FirstSpringTest类中的代码执行记录日志的话,就输出相关的日志信息。
Logger logger = LoggerFactory.getLogger(FirstSpringTest.class);
// 第二步:记录日志,根据不同的级别来输出日志
logger.info("我是一条消息");
logger.debug("我是一条调试信息");
logger.error("我是一条错误信息");
}
四、Spring对IoC的实现
4.1 IoC 控制反转
4.2 依赖注⼊
4.2.1 set注⼊
UserDao类:
public class UserDao {
private static final Logger logger= LoggerFactory.getLogger(UserDao.class);
public void insert(){
//使用log4j2日志框架
logger.info("数据库正在保存用户信息..........");
}
}
vipDao类:
public class VipDao {
private static final Logger logger= LoggerFactory.getLogger(VipDao.class);
public void insert(){
//使用log4j2日志框架
logger.info("正在保存VIP信息..........");
}
}
UserService类:
public class UserService {
private UserDao userDao;
private VipDao vipDao;
//set注入的话,必须要提供一个set方法
//Spring容器会调用这个set方法,来给userDao属性赋值
//这个set方法是IDEA工具生成的,符合javabean规范
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}
// 我自己写一个set方法,不使用IDEA工具生成的。不符合javabean规范。
// 至少这个方法是以set单词开始的。前三个字母不能随便写,必须是“set"
/*public void setMySQLUserDao(UserDao xyz){
this.userDao = xyz;
}*/
public void setVipDao(VipDao vipDao) {
this.vipDao = vipDao;
}
public void saveUser(){
//保存用户信息到数据库
userDao.insert();
vipDao.insert();
}
}
spring.xml:
<bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>
<bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
<!-- 想让Spring调用对应的set方法,需要配置property标签 -->
<!-- name属性怎么指定值:set方法的方法名,去掉set,然后把剩下的单词首字母变小写,写到这里。-->
<!-- ref翻译为引用。英语单词:references。ref后面指定的是要注入的bean的id。-->
<!--<property name="mySQLUserDao" ref="userDaoBean"/>-->
<!--set方法起名的时候,不要为难自己,按照规范来。所以一般情况下name位置写属性名就行了。-->
<property name="userDao" ref="userDaoBean"/>
<property name="vipDao" ref="vipDaoBean"/>
</bean>
<bean id="vipDaoBean" class="com.powernode.spring6.dao.VipDao"/>
SpringDITest类:
@Test
public void testSetDI(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userService= applicationContext.getBean("userServiceBean", UserService.class);
userService.saveUser();
//2023-08-05 15:44:10 362 [main] INFO com.powernode.spring6.dao.UserDao - 数据库正在保存用户信息..........
//2023-08-05 15:51:54 210 [main] INFO com.powernode.spring6.dao.VipDao - 正在保存VIP信息..........
}
4.2.2 构造注⼊
public class CustomerService {
private UserDao userDao;
private VipDao vipDao;
//构造方法注入
public CustomerService(UserDao userDao, VipDao vipDao) {
this.userDao = userDao;
this.vipDao = vipDao;
}
public void save() {
userDao.insert();
vipDao.insert();
}
}
beans.xml:
<bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>
<bean id="vipDaoBean" class="com.powernode.spring6.dao.VipDao"/>
<bean id="csBean" class="com.powernode.spring6.service.CustomerService">
<!--构造注入-->
<!--
index属性指定参数下标,第一个参数是0,第二个参数是1,第三个参数是2,以此类推。
ref属性用来指定注入的bean的id
-->
<!--根据构造方法的下标注入-->
<!--指定构造方法的第一个参数,下标是0-->
<constructor-arg index="0" ref="userDaoBean"/>
<!--指定构造方法的第二个参数,下标是1-->
<constructor-arg index="1" ref="vipDaoBean"/>
</bean>
<bean id="csBean2" class="com.powernode.spring6.service.CustomerService">
<!--根据构造方法的名字注入-->
<constructor-arg name="userDao" ref="userDaoBean"/>
<constructor-arg name="vipDao" ref="vipDaoBean"/>
</bean>
<bean id="csBean3" class="com.powernode.spring6.service.CustomerService">
<!--不指定下标,也不指定名字,让spring自己做类型匹配推断-->
<!--这种方式实际上是根据类型进行注入的,spring会自动根据类型来判断把ref注入给哪个参数-->
<constructor-arg ref="vipDaoBean"/>
<constructor-arg ref="userDaoBean"/>
</bean>
SpringTest类:
@Test
public void testConstructorDI(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
CustomerService csBean = applicationContext.getBean("csBean", CustomerService.class);
csBean.save();
// 2023-08-05 16:56:41 845 [main] INFO com.powernode.spring6.dao.UserDao - 数据库正在保存用户信息..........
// 2023-08-05 16:56:41 847 [main] INFO com.powernode.spring6.dao.VipDao - 正在保存VIP信息..........
CustomerService csBean2 = applicationContext.getBean("csBean2", CustomerService.class);
csBean2.save();
CustomerService csBean3 = applicationContext.getBean("csBean3", CustomerService.class);
csBean3.save();
}
4.3 set注⼊专题
4.3.1 注⼊外部Bean
set-di.xml:
<!--外部Bean-->
<!--声明Bean,或者定义Bean-->
<bean id="orderDaoBean" class="com.powernode.spring6.dao.OrderDao"/>
<bean id="orderServiceBean" class="com.powernode.spring6.service.OrderService">
<!--注入外部Bean,使用ref属性来引入,这就是注入外部Bean-->
<property name="orderDao" ref="orderDaoBean"/>
</bean>
@Test
public void testSetDI2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
OrderService orderServiceBean = applicationContext.getBean("orderServiceBean", OrderService.class);
orderServiceBean.generate();
//2023-08-09 09:56:41 920 [main] INFO com.powernode.spring6.dao.OrderDao - 订单正在生成
}
4.3.2 注⼊内部Bean
<!--内部Bean-->
<bean id="orderServiceBean2" class="com.powernode.spring6.service.OrderService">
<property name="orderDao">
<!--在property标签中使用嵌套的bean标签,这既是内部Bean-->
<bean class="com.powernode.spring6.dao.OrderDao"></bean>
</property>
</bean>
@Test
public void testSetDI2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
OrderService orderServiceBean2 = applicationContext.getBean("orderServiceBean2", OrderService.class);
orderServiceBean2.generate();
//2023-08-09 10:00:23 675 [main] INFO com.powernode.spring6.dao.OrderDao - 订单正在生成
}
4.3.3 注⼊简单类型
public class UserService{
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
}
public class User {
private String username;
private String password;
private int age;
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
'}';
}
}
set-di.xml:
<!--注入简单类型-->
<bean id="userBean" class="com.powernode.spring6.bean.User">
<!--如果给简单类型赋值,就不能使用ref了,要使用value了-->
<property name="username" value="张三"/>
<property name="password" value="123456"/>
<property name="age" value="20"/>
</bean>
@Test
public void testSimpletypeSet(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);//User{username='张三', password='123456', age=20}
}
public static boolean isSimpleValueType(Class<?> type) {
return (Void.class != type && void.class != type &&
(ClassUtils.isPrimitiveOrWrapper(type) ||
Enum.class.isAssignableFrom(type) ||
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
URI.class == type ||
URL.class == type ||
Locale.class == type ||
Class.class == type));
}
//........
}
//测试简单类型
public class SimpleValueType {
private int age;
private Integer age2;
private boolean flag;
private Boolean flag2;
private char c;
private Character c2;
private Season season;
private String username;
private Class clazz;
private Date birth;
后面提供set方法和toString方法
Season枚举类:
public enum Season {
SPRING,SUMMER,AUTUMN,WINTER
}
set-di.xml文件:
<!--测试哪些类型是简单类型-->
<bean id="svt" class="com.powernode.spring6.bean.SimpleValueType">
<property name="age" value="18"/>
<property name="age2" value="19"/>
<property name="c" value="男"/>
<property name="c2" value="女"/>
<property name="clazz" value="java.lang.String"/>
<property name="flag" value="false"/>
<property name="flag2" value="true"/>
<property name="season" value="SPRING"/>
<property name="username" value="猪猪侠"/>
<!--报错了,说2023-06-15这个字符串无法转换成java.util.Date类型-->
<!-- <property name="birth" value="2023-06-15"/>-->
<!--如果你硬要把Date当做简单类型的话,使用value赋值的话,这个日期字符串格式有要求-->
<!--在实际开发中,我们一般不会把Date当做简单类型,虽然它是简单类型。一般会采用ref给Date类型的属性赋值。-->
<property name="birth" value="Wed Oct 19 16:28:13 CST 2022"/>
</bean>
@Test
public void testSimpletypeSet(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);//User{username='张三', password='123456', age=20}
System.out.println("==============================");
SimpleValueType svt = applicationContext.getBean("svt", SimpleValueType.class);
System.out.println(svt);
//SimpleValueType{age=18, age2=19, flag=false, flag2=true, c=男, c2=女, season=SPRING, username='猪猪侠', clazz=class java.lang.String, birth=Thu Oct 20 06:28:13 CST 2022}
}
//所有的数据源都要实现java规范:java.sql.DataSource
//什么是数据源:能够给你提供Connection对象的,都是数据源
public class MyDateSource implements DataSource {//可以把数据源交给Spring容器来管理
private String url;
private String driver;
private String username;
private String password;
后面set方法和toString方法
还有实现DataSource的方法
set-di.xml文件:
<!--让spring来管理我们的数据源-->
<bean id="myDatasource" class="com.powernode.spring6.jdbc.MyDateSource">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring6"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
@Test
public void testMyDataSource(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
MyDateSource myDatasource = applicationContext.getBean("myDatasource", MyDateSource.class);
System.out.println(myDatasource);
//MyDateSource{url='jdbc:mysql://localhost:3306/spring6', driver='com.mysql.cj.jdbc.Driver', username='root', password='123456'}
}
4.3.4 注⼊数组
public class QianDaYe {
private String[] aiHaos;
public void setAiHaos(String[] aiHaos) {
this.aiHaos = aiHaos;
}
@Override
public String toString() {
return "QianDaYe{" +
"aiHaos=" + Arrays.toString(aiHaos) +
'}';
}
}
spring-array.xml文件:
<bean id="yuQian" class="com.powernode.spring6.bean.QianDaYe">
<!--这个数组属性当中的元素类型是String简单类型-->
<property name="aiHaos">
<array>
<value>抽烟</value>
<value>喝酒</value>
<value>烫头</value>
</array>
</property>
</bean>
@Test
public void testArray(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-array.xml");
QianDaYe yuQian = applicationContext.getBean("yuQian", QianDaYe.class);
System.out.println(yuQian);//QianDaYe{aiHaos=[抽烟, 喝酒, 烫头]}
}
public class Woman {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Woman{" +
"name='" + name + '\'' +
'}';
}
}
QianDaYe类:
public class QianDaYe {
private String[] aiHaos;
private Woman[] womens;
public void setWomens(Woman[] womens) {
this.womens = womens;
}
public void setAiHaos(String[] aiHaos) {
this.aiHaos = aiHaos;
}
@Override
public String toString() {
return "QianDaYe{" +
"aiHaos=" + Arrays.toString(aiHaos) +
", womens=" + Arrays.toString(womens) +
'}';
}
}
spring-array.xml类:
<bean id="w1" class="com.powernode.spring6.bean.Woman">
<property name="name" value="小花"/>
</bean>
<bean id="w2" class="com.powernode.spring6.bean.Woman">
<property name="name" value="小亮"/>
</bean>
<bean id="w3" class="com.powernode.spring6.bean.Woman">
<property name="name" value="小明"/>
</bean>
<bean id="yuQian" class="com.powernode.spring6.bean.QianDaYe">
<!--这个数组属性当中的元素类型是String简单类型-->
<property name="aiHaos">
<array>
<value>抽烟</value>
<value>喝酒</value>
<value>烫头</value>
</array>
</property>
<!--这个数组当中不是简单类型了-->
<property name="womens">
<array>
<ref bean="w1"/>
<ref bean="w2"/>
<ref bean="w3"/>
</array>
</property>
</bean>
@Test
public void testArray(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-array.xml");
QianDaYe yuQian = applicationContext.getBean("yuQian", QianDaYe.class);
System.out.println(yuQian);//QianDaYe{aiHaos=[抽烟, 喝酒, 烫头]}
//QianDaYe{aiHaos=[抽烟, 喝酒, 烫头], womens=[Woman{name='小花'}, Woman{name='小亮'}, Woman{name='小明'}]}
}
4.3.5 注⼊List集合和Set集合
public class Person {
//注入List集合
private List<String> names;
//注入set集合
private Set<String> addrs;
public void setNames(List<String> names) {
this.names = names;
}
public void setAddrs(Set<String> addrs) {
this.addrs = addrs;
}
@Override
public String toString() {
return "Person{" +
"names=" + names +
", addrs=" + addrs +
'}';
}
}
spring-collection.xml文件:
<bean id="personBean" class="com.powernode.spring6.bean.Person">
<property name="names">
<!--list是有序可重复的-->
<list>
<value>张山</value>
<value>李四</value>
<value>王五</value>
<value>张山</value>
</list>
</property>
<property name="addrs">
<!--set集合无序不可重复-->
<set>
<value>北京大兴区</value>
<value>北京大兴区</value>
<value>北京海淀区</value>
<value>北京海淀区</value>
</set>
</property>
</bean>
@Test
public void testCollection(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-collection.xml");
Person personBean = applicationContext.getBean("personBean", Person.class);
System.out.println(personBean);//Person{names=[张山, 李四, 王五, 张山], addrs=[北京大兴区, 北京海淀区]}
}
4.3.6 注⼊Map集合
Person类:
private Map<Integer, String> phones;
public void setPhones(Map<Integer, String> phones) {
this.phones = phones;
}
spring-collection.xml文件:
<property name="phones">
<map>
<entry key="1" value="110"/>
<entry key="2" value="119"/>
<entry key="3" value="120"/>
<entry key="4" value="10086"/>
</map>
</property>
@Test
public void testCollection(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-collection.xml");
Person personBean = applicationContext.getBean("personBean", Person.class);
System.out.println(personBean);//Person{names=[张山, 李四, 王五, 张山], addrs=[北京大兴区, 北京海淀区]}
//phones={1=110, 2=119, 3=120, 4=10086}}
}
4.3.7 注⼊Properties
//注入属性类
//Properties本质上也是一个Map集合
//Properties的父类Hashtable,Hashtable实现了Map接口
//显然这个也是一个Map集合,但是和Map的注入方式有点像,但是不同
//Properties的key和Value只能是String类型,不能是别的
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
spring-collection.xml文件:
<property name="properties">
<props>
<prop key="driver">com.mysql.cj.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306/spring6</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
@Test
public void testCollection(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-collection.xml");
Person personBean = applicationContext.getBean("personBean", Person.class);
System.out.println(personBean);//Person{names=[张山, 李四, 王五, 张山], addrs=[北京大兴区, 北京海淀区]}
//phones={1=110, 2=119, 3=120, 4=10086}}
//properties={password=123456, driver=com.mysql.cj.jdbc.Driver, url=jdbc:mysql://localhost:3306/spring6, username=root}}
}
4.3.8 注⼊null和空字符串
public class Cat {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
set-di.xml文件:
<bean id="catBean" class="com.powernode.spring6.bean.Cat">
<!--不给属性注入,属性的默认值是null-->
<!--<property name="name" value="null"/>-->
<!--这不是注入null,这是给属性注入了一个null的字符串-->
<!--这种方式是手动注入null-->
<!--<property name="name">
<null/>
</property>-->
<!--注入空字符串第一种方式-->
<!--<property name="name" value=""/>-->
<!--注入空字符串第二种方式-->
<!--<property name="name" value="tom"/>-->
<property name="age" value="18"/>
</bean>
@Test
public void testNull(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
Cat catBean = applicationContext.getBean("catBean", Cat.class);
System.out.println(catBean); //Cat{name='tom', age=18}
//Cat{name='null', age=18}
}
4.3.9 注⼊的值中含有特殊符号
MathBean类:
public class MathBean {
private String result;
public void setResult(String result) {
this.result = result;
}
@Override
public String toString() {
return "MathBean{" +
"result='" + result + '\'' +
'}';
}
}
set-di.xml文件:
<bean id="mathBean" class="com.powernode.spring6.bean.MathBean">
<!--第一种方案:使用实体符号代替特殊符号-->
<!--<property name="result" value="2 < 3" />-->
<!--第二种方案:使用<![CDATA[]]>-->
<property name="result">
<!--只能使用value标签-->
<value><![CDATA[2 < 3]]></value>
</property>
</bean>
@Test
public void testSpecial(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
MathBean mathBean = applicationContext.getBean("mathBean", MathBean.class);
System.out.println(mathBean);//MathBean{result='2 < 3'}
}
4.4 p命名空间注⼊
public class Dog {
//简单类型
private String name;
private int age;
//非简单类型
private Date birth;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setBirth(Date birth) {
this.birth = birth;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", birth=" + birth +
'}';
}
}
spring-p.xml文件:
xmlns:p="http://www.springframework.org/schema/p"
<!--
第一步:在spring的配置文件头部添加p命名空间。xmlns:p="http://www.springframework.org/schema/p"
第二步:使用 p:属性名 = "属性值"
-->
<bean id="dogBean" class="com.powernode.spring6.bean.Dog" p:name="小花" p:age="3" p:birth-ref="birthBean"/>
<!--这里获取当前系统时间-->
<bean id="birthBean" class="java.util.Date"/>
@Test
public void testP(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-p.xml");
Dog dogBean = applicationContext.getBean("dogBean", Dog.class);
System.out.println(dogBean);//Dog{name='小花', age=3, birth=Wed Aug 09 21:34:01 CST 2023}
}
4.5 c命名空间注⼊
public class People {
private String name;
private int age;
private boolean sex;
//c命名空间是简化构造注入的
//c命名空间注入方法是基于构造方法的
public People(String name, int age, boolean sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
}
spring-c.xml文件:
xmlns:c="http://www.springframework.org/schema/c"
<!--
第一步:在spring的配置文件头部添加: xmlns:c="http://www.springframework.org/schema/c"
第二步:使用
c:_0 下标方式
c:name 参数名方式
-->
<bean id="peopleBean" class="com.powernode.spring6.bean.People" c:_0="张三" c:age="100" c:sex="true"/>
@Test
public void testC(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-c.xml");
People peopleBean = applicationContext.getBean("peopleBean", People.class);
System.out.println(peopleBean);//People{name='张三', age=100, sex=true}
}
4.6 util命名空间
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd ">
public class MyDataSource1 implements DataSource {
//连接数据库的信息
/* private String driver;
private String url;
private String username;
private String password;*/
//Properties属性类对象,这是一个Map集合,key和Value都是string类型
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "MyDataSource1{" +
"properties=" + properties +
'}';
}
后面跟DataSource实现方法
}
public class MyDataSource2 implements DataSource {
//Properties属性类对象,这是一个Map集合,key和Value都是string类型
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "MyDataSource1{" +
"properties=" + properties +
'}';
}
后面跟Datasource实现方法
}
spring-util.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd ">
<!--引入util命名空间
在spring的配置文件头部添加:
xmlns:util="http://www.springframework.org/schema/util"
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
-->
<util:properties id="prop">
<prop key="drive">com.mysql.cj.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306/spring6</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</util:properties>
<!--数据源1-->
<bean id="ds1" class="com.powernode.spring6.jdbc.MyDataSource1">
<property name="properties" ref="prop"/>
</bean>
<!--数据源2-->
<bean id="ds2" class="com.powernode.spring6.jdbc.MyDataSource2">
<property name="properties" ref="prop"/>
</bean>
</beans>
@Test
public void testUtil(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-util.xml");
MyDataSource1 ds1 = applicationContext.getBean("ds1", MyDataSource1.class);
MyDataSource2 ds2 = applicationContext.getBean("ds2", MyDataSource2.class);
System.out.println(ds1);
System.out.println(ds2);
// MyDataSource1{properties={password=123456, drive=com.mysql.cj.jdbc.Driver, url=jdbc:mysql://localhost:3306/spring6, username=root}}
// MyDataSource1{properties={password=123456, drive=com.mysql.cj.jdbc.Driver, url=jdbc:mysql://localhost:3306/spring6, username=root}}
}
4.7 基于XML的⾃动装配
4.7.1 根据名称⾃动装配
OrderDao类:
public class OrderDao {
private static final Logger logger = LoggerFactory.getLogger(OrderDao.class);
public void insert(){
logger.info("订单正在生成");
}
}
OrderService类:
public class OrderService {
private OrderDao orderDao;
//通过set属性给方法赋值
public void setOrderDao(OrderDao orderDao){
this.orderDao=orderDao;
}
//生成订单的业务方法
public void generate(){
orderDao.insert();
}
}
spring-autowire.xml文件:
<!--根据名字进行自动装配-->
<!-- 注意:自动装配也是基于set方式实现的-->
<bean id="orderService" class="com.powernode.spring6.service.OrderService" autowire="byName"></bean>
<!--id一般叫做bean的名称-->
<!--根据名字进行自动装配的时候,被注入的对象的bean的id不能随便写,怎么写?set方法的方法名去掉set,剩下单词首字母小写。-->
<bean id="orderDao" class="com.powernode.spring6.dao.OrderDao"/>
<!-- <bean id="orderDao" class="com.powernode.spring6.dao.OrderDao"/>-->
<!-- <bean id="orderService" class="com.powernode.spring6.service.OrderService">-->
<!-- <property name="orderDao" ref="orderDao"/>-->
<!-- </bean>-->
@Test
public void testAutowire(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
orderService.generate();
//2023-08-09 22:22:15 704 [main] INFO com.powernode.spring6.dao.OrderDao - 订单正在生成
}
4.7.2 根据类型⾃动装配
UserDao类:
public class UserDao {
private static final Logger logger= LoggerFactory.getLogger(UserDao.class);
public void insert(){
//使用log4j2日志框架
logger.info("数据库正在保存用户信息..........");
}
}
VipDao类:
public class VipDao {
private static final Logger logger= LoggerFactory.getLogger(VipDao.class);
public void insert(){
//使用log4j2日志框架
logger.info("正在保存VIP信息..........");
}
}
CustomerService类:
public class CustomerService {
private UserDao userDao;
private VipDao vipDao;
//构造方法注入
// public CustomerService(UserDao userDao, VipDao vipDao) {
// this.userDao = userDao;
// this.vipDao = vipDao;
// }
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setVipDao(VipDao vipDao) {
this.vipDao = vipDao;
}
public void save() {
userDao.insert();
vipDao.insert();
}
}
spring-autowire.xml文件:
<!--根据类型进行自动装配-->
<!--自动装配是基于set方法的-->
<!--根据类型进行自动装配的时候,在有效的配置文件当中,某种类型的实例只能有一个。-->
<bean class="com.powernode.spring6.dao.VipDao"></bean>
<bean class="com.powernode.spring6.dao.UserDao"></bean>
<!--<bean id="y" class="com.powernode.spring6.dao.UserDao"></bean>-->
<bean id="cs" class="com.powernode.spring6.service.CustomerService" autowire="byType"></bean>
@Test
public void testAutowire(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");
OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
orderService.generate();
//2023-08-09 22:22:15 704 [main] INFO com.powernode.spring6.dao.OrderDao - 订单正在生成
CustomerService cs = applicationContext.getBean("cs", CustomerService.class);
cs.save();
// 2023-08-09 22:35:10 669 [main] INFO com.powernode.spring6.dao.UserDao - 数据库正在保存用户信息..........
// 2023-08-09 22:35:10 670 [main] INFO com.powernode.spring6.dao.VipDao - 正在保存VIP信息..........
}
4.8 spring引⼊外部属性配置⽂件
//所有的数据源都要实现java规范:java.sql.DataSource
//什么是数据源:能够给你提供Connection对象的,都是数据源
public class MyDataSource implements DataSource {//可以把数据源交给Spring容器来管理
private String url;
private String driver;
private String username;
private String password;
public void setUrl(String url) {
this.url = url;
}
后面跟DataSource实现方法
}
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost/spring6
jdbc.username=root
jdbc.password=123456
<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--
引入外部的properties文件
第一步:引入context命名空间。
第二步:使用标签context:property-placeholder的location属性来指定属性配置文件的路径。
location默认从类的根路径下开始加载资源。
-->
<context:property-placeholder location="jdbc.properties"/>
<!--配置数据源-->
<bean id="ds" class="com.powernode.spring6.jdbc.MyDataSource">
<!--怎么取值呢-->
<property name="driver" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
@Test
public void testProperties() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-properties.xml");
MyDataSource ds = applicationContext.getBean("ds", MyDataSource.class);
System.out.println(ds);
//MyDateSource{url='jdbc:mysql://localhost/spring6', driver='com.mysql.cj.jdbc.Driver', username='root', password='123456'}
}