当前位置: 首页 > news >正文

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博客

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 调度系统之Oozie
  • 【Flutter 自定义字体】等宽字体等
  • 《2024华数杯》C题第四问 模型建立+优化算法
  • 鸿蒙(API 12 Beta2版)NDK开发【LLDB高性能调试器】调试和性能分析
  • C++入门基础(二)
  • C++数学库GNU Scientific Library (GSL)
  • PXE 服务器搭建——启动界面设计实验
  • 1.MySQL面试题之innodb如何解决幻读
  • 基于Spring前后端分离版本的论坛
  • 2024/8/4 汇川变频器低压产品分类选型
  • 174.地下城游戏——LeetCode
  • [windows10]win10永久禁用系统自动更新操作方法
  • 职业生涯阶段总结3:转眼毕业三年
  • Vue路由入门学习
  • 【Java数据结构】---初始数据结构
  • 网络传输文件的问题
  • es的写入过程
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • mongo索引构建
  • MySQL数据库运维之数据恢复
  • npx命令介绍
  • Promise初体验
  • Python进阶细节
  • Vue全家桶实现一个Web App
  • 从PHP迁移至Golang - 基础篇
  • 基于MaxCompute打造轻盈的人人车移动端数据平台
  • 跨域
  • 码农张的Bug人生 - 见面之礼
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • -- 数据结构 顺序表 --Java
  • 一道闭包题引发的思考
  • 一个项目push到多个远程Git仓库
  • 怎么把视频里的音乐提取出来
  • 正则学习笔记
  • #if等命令的学习
  • (1)常见O(n^2)排序算法解析
  • (6) 深入探索Python-Pandas库的核心数据结构:DataFrame全面解析
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (Java数据结构)ArrayList
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (七)Flink Watermark
  • (七)glDrawArry绘制
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • (转)mysql使用Navicat 导出和导入数据库
  • (转)winform之ListView
  • (转)大型网站的系统架构
  • (转载)深入super,看Python如何解决钻石继承难题
  • .gitignore文件设置了忽略但不生效
  • .NET DataGridView数据绑定说明
  • .NET/C# 的字符串暂存池
  • .net的socket示例
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)