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

news2024/11/14 13:59:38

什么是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 通过无参构造帮我们创建对象");
    }

    @Override
    public 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();

        //这里用了别名来获取bean
        StudentDao 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("工厂的无参构造");
    }

    @Override
    public StudentDao getObject() throws Exception {
        return new StudentDaoImpl();  //此乃动态实例化对象的方法
    }

    @Override
    public Class<?> getObjectType() {
        return StudentDao.class; //返回StudentDao的字节码
    }

    @Override
    public 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;


    @Override
    public void selectAll() {
        System.out.println("select all books...");
    }

    @Override
    public 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;
    }

    @Override
    public void selectAll() {
        System.out.println("select all books...");
    }

    @Override
    public 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;
//    }

    @Override
    public void selectAll() {
        System.out.println("select all books...");
    }

    @Override
    public 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/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: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.coloradmin.cn/o/1984859.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

洗牌算法 和 杨辉三角

目录 一、洗牌算法 1.1 Poker 1.2 PokerBox 1.3 Test 二、杨辉三角 一、洗牌算法 【业务需求】&#xff1a; 第一步&#xff1a;生成52张牌&#xff0c;没有大小王&#xff0c;一共四种花色({"♠", "♥", "♣", "♦")&#xff0c…

爬虫中使用多进程、多线程的混合方式遇到的数据丢失问题

项目场景&#xff1a; 网络爬虫项目&#xff0c;主要实现多进程、多线程方式快速缓存网页资源到MongoDB&#xff0c;并解析网页数据&#xff0c;将信息写入到csv文件中。 问题描述 在单独使用多线程的过程中&#xff0c;是没有问题的&#xff0c;比如这个爬虫示例是爬取豆瓣电…

成都云飞浩容文化传媒有限公司共绘电商服务新蓝图

在这个日新月异的电商时代&#xff0c;每一家企业都渴望在浩瀚的互联网海洋中脱颖而出&#xff0c;实现品牌的飞跃式增长。而在这场没有硝烟的战争中&#xff0c;专业的电商服务成为了企业破局的关键。成都云飞浩容文化传媒有限公司&#xff0c;作为电商服务领域的佼佼者&#…

(ABC三题完整内容)2024年华数杯大学生数学建模竞赛解题思路完整代码论文集合

我是Tina表姐&#xff0c;毕业于中国人民大学&#xff0c;对数学建模的热爱让我在这一领域深耕多年。我的建模思路已经帮助了百余位学习者和参赛者在数学建模的道路上取得了显著的进步和成就。现在&#xff0c;我将这份宝贵的经验和知识凝练成一份全面的解题思路与代码论文集合…

【mars3d】加载超图s3m模型说明

建议替换Cesium库&#xff0c;换成 超图版本Cesium mars3d mars3d-supermap &#xff0c;需要引入的资源为&#xff1a; "mars3d": ["Cesium-supermap/Widgets/widgets.css", //超图版本Cesium "Cesium-supermap/Cesium.js","mars3d/plu…

vue使用响应式API和页面组件ref相同名称问题

最近在使用vue3vite学习前端的东西。在学习form表单时发现&#xff0c;<el-form>里面的<el-input>绑定数据时&#xff0c;页面输入框在键盘输入之后没有反应&#xff0c;每次只能输入一各字母。 <template><div class"login-container"><…

电子产品CE认证标准以及欧盟需要做的认证有哪些?

​一、家电产品GB质检报告测试内容有哪些&#xff1f; 1.家用电器的测试内容包括预检测和测试 预检测是指在测试之前判定产品是否符合标准要求的检查&#xff0c;主要包括以下三个方面&#xff1a; 1.1产品铭牌、使用的标志、说明书检查 1.2产品的外观及内部结构检查 1.3产品…

Java程序员接单分享

作为一名Java程序员&#xff0c;这阵子通过承接些小型项目&#xff0c;我顺利跨过了月薪破万的门槛。这些项目虽小&#xff0c;却如同磨刀石般&#xff0c;让我在实战中发现了自身技术栈的棱角与不足&#xff0c;尤其是意识到了在Java这一浩瀚技术海洋中的诸多未知领域。我深知…

Python 爬虫项目实战(六):爬取大众点评商家数据

前言 网络爬虫&#xff08;Web Crawler&#xff09;&#xff0c;也称为网页蜘蛛&#xff08;Web Spider&#xff09;或网页机器人&#xff08;Web Bot&#xff09;&#xff0c;是一种按照既定规则自动浏览网络并提取信息的程序。爬虫的主要用途包括数据采集、网络索引、内容抓…

开放式耳机有哪些优缺点,2024年开放式耳机推荐

&#xff08;一&#xff09;开放式耳机有哪些优缺点 优点&#xff1a;良好的音质&#xff0c;佩戴舒适不伤害耳朵&#xff0c;便于携带&#xff0c;一句话就是舒适又安全&#xff1b; 缺点&#xff1a;最大的缺点就是隔音效果不佳&#xff0c;而且很大的可能性会出现漏音现象…

亚马逊、速卖通卖家必看:自养号测评助力转化率提升

在亚马逊、速卖通等电商平台的激烈竞争中&#xff0c;卖家们深谙流量之于店铺转化率的重要性&#xff0c;而测评补单作为提升业绩的关键策略之一&#xff0c;其重要性不言而喻。它不仅是日常运营中不可或缺的一环&#xff0c;更是助力产品在众多竞品中脱颖而出的竞争利器。特别…

Google Play Instant免安装应用,助力市场推广!

什么是免安装应用&#xff1f; 一句话总结&#xff1a;Google Play 免安装应用就是允许用户在不安装应用的情况下访问应用的内容。 那么它有什么作用呢&#xff1f; 1.增强与用户的互动&#xff0c;推出可吸引用户安装App的活动或者功能进行极致体验&#xff0c;提升安装量并…

09.XSS跨站脚本攻击(超详细!!!)

1、什么是XSS XSS&#xff08;跨站脚本攻击&#xff09;&#xff1a;攻击者利用这个漏洞将恶意脚本注入到网页中&#xff0c;当其它用户浏览这些页面时&#xff0c;恶意脚本会在用户的浏览器中执行。XSS攻击允许攻击者在用户的浏览器上执行脚本&#xff0c;从而可能获取用户的…

好书推荐|大模型必学《Transformer自然语言处理实战》

今天又来给大家分享ai大模型书籍了&#xff0c;今天是这本非常畅销的书----《Transformer自然语言处理实战》涵盖了Transformer在NLP领域的主要应用。 首先介绍Transformer模型和Hugging Face 生态系统。然后重点介绍情感分析任务以及Trainer API、Transformer的架构&#xff…

深入了解App设计流程的7个关键阶段

在当今数字时代&#xff0c;每个人的日常生活都与各种应用密切相关。APP已经成为我们生活中不可或缺的一部分&#xff0c;无论是社交网络、健康服务、购物还是娱乐。优秀的APP设计不仅能提供良好的用户体验&#xff0c;还能吸引用户的注意力&#xff0c;有效传达信息。作为一名…

《python语言程序设计》2018版第6章第33题使用五边形面积,利用函数重写编程3.4题 返回五边形的面积

之前03.04.01version 2024.02.04side_num eval(input("Enter the side: ")) area_num (5 * pow(side_num, 2)) / (4 * math.tan(math.pi / 5)) print("The area of the pentagon is {:>.20f}".format(area_num))本次代码 def area(side_num):side_num…

十分钟带你学会 Vue-router

安装、配置 Router Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成&#xff0c;让构建单页面应用变得易如反掌。 了解路由之前&#xff0c;我们需要先理解一个概念&#xff1a;单页应用。 单页应用 SPA(single page application):单一页面应用程序&am…

【微信小程序实战教程】之微信小程序中的 JavaScript

微信小程序中的 JavaScript 微信小程序的业务逻辑都是通过JavaScript语言来实现的&#xff0c;本章我们将详细的讲解JavaScript的基本概念&#xff0c;以及在小程序中如何使用JavaScript语言。JavaScript是一种轻量的、解释型的、面向对象的头等函数语言&#xff0c;是一种动态…

uniapp用自带的canvas做画板签字

如下图移动端经常需要做此功能,用户签字。用户填表啥的。 先用touch进行监听手指的触摸事件 获取所点击的坐标位置。 这里有很多要注意的地方。 初始化 uniapp里的canvas与原生的canvas有区别,渲染之后会多很多莫名其妙的div节点,并且还有个div直接就把原生的canvas覆盖…

仿真入门必看:怎么用CST软件自带宏提取材料的DK,Df值

我们知道如果在CST中要做精确的仿真&#xff0c;进行仿真测试对比&#xff0c;其中第一步就是要搞清楚仿真模型的参数&#xff0c;如果输入数据不对&#xff0c;那也避免不了垃圾进垃圾出的原则。和仿真相关的数据很多&#xff0c;其中PCB板的介质参数Dk, Df就是介电常数的实部…