SSM项目学习:用xml配置文件或注解开发实现控制反转和依赖注入

什么是SSM

SSM=Spring(Spring Framework)+Spring MVC +mybatis

Spring Framework系统架构

Spring Framework学习线路

IoC(Inversion of Control)和DI(Dependency Injection)

他们解决的问题:代码耦合度高的问题,需要类自己new对象,修改部分代码时,导致"牵一发而动全身"的问题。

Spring提供的IoC容器帮助我们实现控制反转,由IoC容器统一管理我们所要用的容器,需要时只需要从IoC容器获取即可。

我们的业务层类可能需要数据层的实例化对象来实现操作数据库的效果,这时候可以通过依赖注入来建立他们直接的关系,把数据层的实例化对象装配到业务层中。

实现IoC两种配置方式 

XML配置文件开发

在xml文件中配置bean

基本配置:id(独有标识) name(别名,用逗号分割) class(类)

 bean的作用范围

单例模式下,通过getBean得到的对象唯一,原型模式下,得到的对象不唯一。

bean的生命周期

从这里的命名我们也可以看出来init方法是在bean中所有成员都装配完毕后才调用,而不是创建实例化对象时马上调用。 

 

bean实例化的三种方式

1.构造方法创建实例化对象

spring通过无参构造帮我们创建对象,然后再调用里面的方法。

测试案例

StudentDaoImpl实现StudentDao接口

StudentDao

package com.example.test.dao;public interface StudentDao {public void selectAll();
}

StudentDaoImpl

package com.example.test.dao.impl;
import com.example.test.dao.StudentDao;public class StudentDaoImpl implements StudentDao {public StudentDaoImpl() {System.out.println("Spring 通过无参构造帮我们创建对象");}@Overridepublic void selectAll() {System.out.println("student selectAll");}
}

在applicationContext.xml中配置

<!--    1.调用无参构造--><!--    name字段用来取别名,多个别名可以用;分割--><bean id="studentDao" name="dao;daozz" class="com.example.test.dao.impl.StudentDaoImpl"></bean>

测试代码和运行结果: 

import org.springframework.context.support.ClassPathXmlApplicationContext;public class App1 {public static void main(String[] args) {//获取Ioc容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//注册关闭钩子   在关虚拟机之前先关闭容器context.registerShutdownHook();//这里用了别名来获取beanStudentDao studentDao = context.getBean("daozz", StudentDao.class);studentDao.selectAll();}
}

2.通过静态工厂实例化对象
测试案例

静态工厂类(通过静态方法来创建实例化对象)

package com.example.test.factory;
import com.example.test.dao.StudentDao;
import com.example.test.dao.impl.StudentDaoImpl;//静态工厂创建实例化对象
public class StudentDaoFactory1 {private static StudentDao getStudentDao(){System.out.println("工厂的相关配置初始化...");return new StudentDaoImpl();}
}

xml中配置(class填写静态工厂类   factory-method里面填写工厂类中用于实例化对象的静态方法 )

<!--    2.静态工厂实例化对象--><bean id="studentDao" class="com.example.test.factory.StudentDaoFactory1" factory-method="getStudentDao"></bean>

 测试代码及结果

3.通过工厂类中的非静态方法创建实例化对象
测试案例

工厂类

package com.example.test.factory;import com.example.test.dao.StudentDao;
import com.example.test.dao.impl.StudentDaoImpl;
//动态工厂创建实例化对象
public class StudentDaoFactory2 {//注意这是一个非静态方法public StudentDao getStudentDao(){return new StudentDaoImpl();}
}

xml中配置

<!--    3.通过工厂类中的非静态方法创建实例化对象-->
<!--    第一步:配置工厂bean  因为不是静态方法,使用的时候要先创建工厂的实例对象--><bean id="studentDaoFactory" class="com.example.test.factory.StudentDaoFactory2"></bean>
<!--        第二步:指定工厂和里面实例化的方法--><bean id="studentDao" factory-bean="studentDaoFactory" factory-method="getStudentDao"></bean>

 测试代码及结果

4.通过工厂类中的非静态方法创建实例化对象的改进版——实现FactoryBean接口
测试案例

工厂类(顺带测试了下bean的生命周期)

实现了FactoryBean接口   重新getObject方法返回要实例化的对象即可

package com.example.test.factory;import com.example.test.dao.StudentDao;
import com.example.test.dao.impl.StudentDaoImpl;
import org.springframework.beans.factory.FactoryBean;//泛型里面填写要实例化的对象
public class StudentDaoFactory3 implements FactoryBean<StudentDao> {public StudentDaoFactory3() {System.out.println("工厂的无参构造");}@Overridepublic StudentDao getObject() throws Exception {return new StudentDaoImpl();  //此乃动态实例化对象的方法}@Overridepublic Class<?> getObjectType() {return StudentDao.class; //返回StudentDao的字节码}@Overridepublic boolean isSingleton() {return true;  //默认单例模式}//设置容器创建和销毁时调用的方法public void init(){System.out.println("init...");}public void destroy(){System.out.println("destroy...");}
}

xml中配置(顺带配置了初始化方法和销毁方法)

<!--    动态工厂实例化对象的改进版 实现FactoryBean接口--><bean id="studentDao" class="com.example.test.factory.StudentDaoFactory3" init-method="init" destroy-method="destroy"></bean>

 测试代码及结果(属性注入 在 执行工厂无参构造 和 执行init方法 之间执行)

依赖注入 

bean实例化出来了,那么类里面的成员属性和类之间的引用关系要如何实现?Spring提供的依赖注入帮助我们解决这个问题。

1.setter注入

测试案例

bookDaoImpl实现bookDao接口

bookDao

package com.example.test.dao;public interface BookDao {public void selectAll();public void getMsg();
}

bookDaoImpl(注意这里要提供成员属性的setter方法)

package com.example.test.dao.impl;
import com.example.test.dao.BookDao;
import com.example.test.dao.StudentDao;
import com.example.test.dao.TeacherDao;
import lombok.Data;@Data
public class BookDaoImpl implements BookDao {private String libName;private int connectNum;private TeacherDao teacherDao;@Overridepublic void selectAll() {System.out.println("select all books...");}@Overridepublic void getMsg() {System.out.println(libName+"--"+connectNum+"--"+teacherDao);}
}

xml中配置 

<bean id="bookDao" class="com.example.test.dao.impl.BookDaoImpl"><!--        方式1:setter注入,要提供setter方法--><!--        ref是引用类型  value传具体值--><property name="connectNum" value="100"/><property name="libName" value="图书馆名"/><property name="teacherDao" ref="teacherDao"/></bean>

测试代码及结果

2.构造器注入

 测试案例

bookDaoImpl中需要提供带参数的构造方法(要注入哪个成员就往里面写)

package com.example.test.dao.impl;
import com.example.test.dao.BookDao;
import com.example.test.dao.StudentDao;
import com.example.test.dao.TeacherDao;
import lombok.Data;@Data
public class BookDaoImpl implements BookDao {private String libName;private int connectNum;private TeacherDao teacherDao;public BookDaoImpl(String libName, int connectNum, TeacherDao teacherDao) {this.libName = libName;this.connectNum = connectNum;this.teacherDao = teacherDao;}@Overridepublic void selectAll() {System.out.println("select all books...");}@Overridepublic void getMsg() {System.out.println(libName+"--"+connectNum+"--"+teacherDao);}
}

 xml中配置

    <bean id="bookDao" class="com.example.test.dao.impl.BookDaoImpl"><!--        方式1:setter注入,要提供setter方法--><!--        ref是引用类型  value传具体值-->
<!--        <property name="connectNum" value="100"/>-->
<!--        <property name="libName" value="图书馆名"/>-->
<!--        <property name="teacherDao" ref="teacherDao"/>-->
<!--        方式2:构造器注入--><constructor-arg name="connectNum" value="100"/><constructor-arg name="libName" value="图书馆名"/><constructor-arg name="teacherDao" ref="teacherDao"/></bean>

代码和测试结果同上 

3.自动装配

测试案例 

bookDaoImpl

package com.example.test.dao.impl;
import com.example.test.dao.BookDao;
import com.example.test.dao.StudentDao;
import com.example.test.dao.TeacherDao;
import lombok.Data;@Data
public class BookDaoImpl implements BookDao {
//    private String libName;
//    private int connectNum;private TeacherDao teacherDao;private StudentDao studentDao;//    public BookDaoImpl(String libName, int connectNum, TeacherDao teacherDao) {
//        this.libName = libName;
//        this.connectNum = connectNum;
//        this.teacherDao = teacherDao;
//    }@Overridepublic void selectAll() {System.out.println("select all books...");}@Overridepublic void getMsg() {
//        System.out.println(libName+"--"+connectNum+"--"+teacherDao);System.out.println(studentDao+"--"+teacherDao);}
}

xml中配置

    <bean id="teacherDao" class="com.example.test.dao.impl.TeacherDaoImpl"/><bean id="studentDao" name="dao;daozz" class="com.example.test.dao.impl.StudentDaoImpl"></bean><bean id="bookDao" class="com.example.test.dao.impl.BookDaoImpl" autowire="byName">
<!--        方式3:自动装配-->
<!--        autowire=byType/byName/constructor--></bean>

 byType情况下要保证要注入的bean类型唯一

byName情况下要保证要注入的成员的名字和xml文件里面bean的id匹配得上

测试代码及结果

依赖注入方式选择

 自动装配要注意byType情况下要注意不能有相同类型的bean  byName要注意名字是否匹配,在xml配置文件开发下更推荐使用前面两种。 

注入集合对象

采用setter注入

TestCollection类

package com.example.test.service.impl;
import lombok.Data;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@Data
//要提供setter方法
public class TestCollection {private int[] myArray;private List<String> myList;private Set<String> mySet;private Map<String,Integer> myMap;private Properties myProperties;
}

xml中配置

    <bean id="testCollection" class="com.example.test.service.impl.TestCollection"><property name="myArray"><array><value>1</value><value>2</value><value>3</value></array></property><property name="myList"><list><value>哈哈</value><value>"呵呵"</value><value>1+六</value></list></property><property name="mySet"><set>
<!--                不重复--><value>赵</value><value>钱</value><value>钱</value><value>陈</value></set></property><property name="myMap"><map>
<!--                被覆盖--><entry key="张三" value="123"/><entry key="张三" value="456"/><entry key="李四" value="789"/><entry key="王五" value="666"/></map></property><property name="myProperties"><props><prop key="url">jdbc:mysql://localhost:3306/testspring</prop><prop key="driver">com.mysql.jdbc.Driver</prop><prop key="username">root</prop><prop key="password">root</prop></props></property></bean>

测试代码及测试结果

第三方bean的导入

测试代码及结果

优化(加载Properties)

创建context命名空间

<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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--    加载properties文件--><context:property-placeholder location="db.properties" system-properties-mode="NEVER"/>

用${param} 

<!--    加载第三方bean--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--        driverClassName≠dirver--><property name="driverClassName" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></bean>

 创建IoC容器,获取bean的几种方法和懒加载

创建IoC容器

获取bean

懒加载 

容器结构层次图

ApplicationContext默认立即加载  BeanFactory默认延迟加载

测试案例

请注意这里的TestLazy没有被其他任何bean引用,否则其他bean在创建的时候会装配TestLazy并创建它的实例化对象

eg1:未开启懒加载,上下文对象被创建时自动调用了无参构造。

 

eg2:开启懒加载,没有调用这个bean,就不会调用它的无参构造。 

总结

注解开发

Spring注解开发-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/392462.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

03、DQL(数据查询语句)

目录 1、编写顺序 2、基本查询 3、条件查询 4、聚合函数 5、分组查询 6、排序查询 7、分页查询 8、执行顺序 1、编写顺序 SELECT 字段列表 FROM 表名列表 WHERE 条件列表 GROUP BY 分组字段列表 HAVING 分组后条件列表 ORDER BY 排序字段列表 LIMIT 分页参数2、基本查…

简单的docker学习 第11章 镜像中心

第11章 镜像中心 Docker Hub 与阿里云都是 Docker 的公网镜像中心&#xff0c;用户可以将自己的镜像 push 到公网镜像中心中自己的镜像仓库&#xff0c;并可将仓库设置为私有库&#xff0c;使他人无法看到&#xff0c;更无法 pull&#xff0c;以保证镜像的安全性。不过&#x…

【LeetCode刷题笔记】LCR.27 回文链表

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 更多算法知识专栏&#xff1a;算法分析&#x1f525; 给大家跳段街舞感谢…

为什么康耐视visionpro的C#二次开发调用的recorddisplay控件偶尔会显示白色的,偶尔又正常了?

recorddisplay控件正常显示 异常显示 原因分析&#xff1a; 没有完全加载recorddisplay控件&#xff0c;有可能是有bug没有完全加载&#xff0c;打断点调试控件是否完全加载。

EMQX服务器安装MQTT测试

cd /usr/local/develop wget https://www.emqx.com/en/downloads/broker/5.7.1/emqx-5.7.1-el7-amd64.tar.gz mkdir -p emqx && tar -zxvf emqx-5.7.1-el7-amd64.tar.gz -C emqx ./emqx/bin/emqx start 重启 ./emqx/bin/emqx restart http://10.8.0.1:18083/ 账号ad…

【Kubernetes】应用的部署(一):金丝雀部署

应用的部署&#xff08;一&#xff09;&#xff1a;金丝雀部署 在项目迭代开发过程中&#xff0c;经常需要对应用进行上线部署。上线部署策略主要有 3 种&#xff1a;金丝雀部署、蓝绿部署 和 滚动部署。 金丝雀部署 也被叫作 灰度部署。金丝雀部署过程&#xff1a;先让一部分…

letcode 分类练习 哈希表 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和

letcode 分类练习 哈希表 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和 242.有效的字母异位词349.两个数组的交集202.快乐数1.两数之和 242.有效的字母异位词 分别定义两个字母哈希表就可以了 class Solution { public:bool isAnagram(string s, strin…

搭建pxe网络安装环境

实验目的&#xff1a; 搭建pxe网络安装环境实现服务器自动部署 实验原理&#xff1a; PXE 网络安装环境实现服务器自动部署的实验原理为&#xff1a; 待安装的服务器&#xff08;PXE 客户端&#xff09;开机时&#xff0c;BIOS 设置从网络启动&#xff0c;向网络发送请求。…

科普文:JUC系列之ForkJoinPool源码解读ForkJoinWorkerThread

科普文&#xff1a;JUC系列之ForkJoinPool基本使用及原理解读-CSDN博客 科普文&#xff1a;JUC系列之ForkJoinPool源码解读概叙-CSDN博客 科普文&#xff1a;JUC系列之ForkJoinPool源码解读WorkQueue-CSDN博客 科普文&#xff1a;JUC系列之ForkJoinPool源码解读ForkJoinTask…

【第13章】Spring Cloud之Gateway全局异常处理

文章目录 前言一、异常处理1. 响应实体类2. 异常处理类 二、单元测试1. 无可用路由2. 服务不可用 总结 前言 网关作为我们对外服务的入口起着至关重要的作用&#xff0c;我们必须保证网关服务的稳定性&#xff0c;下面来为网关服务增加异常处理机制。 一、异常处理 1. 响应实…

K个一组翻转链表(LeetCode)

题目 给你链表的头节点 &#xff0c;每 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 的整数倍&#xff0c;那么请将最后剩余的节点保持原有顺序。 你不能只是单纯的改变节点内部的值&…

UE GAS学习

【Unreal】虚幻GAS系统快速入门-CSDN博客 GameplayTags FGameplayTags是一种层级标签&#xff0c;如Parent.Child.GrandChild。 通过GameplayTagManager进行注册。替代了原来的Bool&#xff0c;或Enum的结构&#xff0c;可以在玩法设计中更高效地标记对象的行为或状态。 Gamep…

牛客周赛 Round 54 (A~E)

#牛客周赛 Round 54 &#xff08;A~E&#xff09; 前言&#xff1a; 以后会定时更新很多比赛的题解 希望借此让自己坚持赛后补题 要不然写完就结束 自己水平没有一点提高 本人很菜所以不会更新 太难的题 加油&#xff01;&#xff01;&#xff01;1. ​清楚姐姐的糖葫芦…

C语言之递归函数

文章目录 &#x1f34a;自我介绍&#x1f34a;递归函数 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xff08;一键四连&#xff09;哦~ &#x1f34a;自我介绍 Hello,大家好&#xff0c;我是小珑也要变强&#xff08;也是小珑&…

C#学习笔记12:SYN6288语音模块_Winform上位机控制软件

今日尝试使用C# Winform写一个上位机软件控制 SYN6288语音模块 这里不讲什么基本原理(或者讲的比较略简)&#xff0c;直接讲实现了就...... 文章提供测试代码讲解、测试效果图、整体测试工程下载 目录 控件的摆放&#xff1a; SYN6288介绍: 代码编程&#xff1a; 对16进制发送…

VUE.js

目录 一、什么是VUE.js 二、VUE.js优点 三、VUE安装 四、第一个VUE程序 五、Vue指令 v-text v-html v-on v-model v-show v-if v-bind v-for 六、VUE实例生命周期 七、Vue-CLI搭建项目 主要的功能 需要的环境 八、组件路由 搭建步骤: 1. 创建 router 目录 …

ctfhub 命令注入

知识点 1.常见的拼接符 1、A ; B 先执行A&#xff0c;再执行B 2、A & B 简单的拼接 3、A | B 显示B的执行结果 4、A&&B A执行成功之后才会执行B 5、A || B A执行失败之后才会执行B , 在特殊情况下可代替空格 2.常见的命令 &#…

CentOS7 VMware虚拟机基于NAT配置网络IP

目录 前言 VMnet8 虚拟网络编辑 ens33 ping 防火墙 前言 平时学习时一直需要用到Linux服务器&#xff0c;一般都是在Windows上安装VMware来创建一个虚拟机。创建的虚拟机需要配置网络才能够访问外网&#xff0c;可以通过以下两种方式来配置虚拟机网络 桥接模式NAT模式&…

「测试线排查的一些经验-上篇」 后端工程师

文章目录 端口占用脚本失灵线上部署项目结构模版配置文件生效 一般产品研发过程所使用的环境可分为&#xff1a; 研发环境-dev测试环境-test生产环境-prod 软件开发中&#xff0c;完整测试环境包括&#xff1a;UT、IT、ST、UAT UT Unit Test 单元测试 IT System Integration …

MoE-LLaVA: Mixture of Experts for Large Vision-Language Models

发表时间&#xff1a;6 Jul 2024 论文链接&#xff1a;https://arxiv.org/pdf/2401.15947 作者单位&#xff1a;Peking University Motivation&#xff1a;最近的进展表明&#xff0c;扩展大型视觉语言模型 (LVLM) 有效地提高了下游任务的性能。然而&#xff0c;现有的缩放方…