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

【spring】原生xml配置版

1.概念

在 Java 项目开发过程中,耦合性是一个需要重点关注的问题。尤其是在项目后期进行功能的增加或删除时,最好避免直接修改源代码。为解决这一问题,通常会采用工厂模式结合反射模式来实现解耦。然而,这种方式存在一个弊端,即每次都需要重复创建类的实例化对象,从而导致资源开销增大。Spring 框架的出现则有效地解决了这些问题。Spring 通过将需要实例化的类纳入 Spring IoC(控制反转)容器进行管理,当需要使用类中的方法时,可直接调用容器中相关类的 Bean

小tips:一定要搞清楚bean的意思,在spring中可以就把它理解为类的实例化对象,不然后面一直提到bean就会很晕 

2.spring入门环境的搭建

首先在pom.xml文件中导入关于spring的核心依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
    </dependencies>

这里也可以使用其他的版本

然后要去定义dao service的接口及其实现类,接着在resources包中创建xml文件,通过bean的标签来管理bean,将bean放在spring的ioc容器中

    <bean id="accountDao" class="com.xq.dao.Impl.AccountDaoImpl"/>
    <bean id="accountService" class="com.xq.service.impl.AccountServiceImpl"/>

这里的id的值是任意的,但是它必须是唯一的,class值就是你想要实现的类的工程中的路径 ,

在配置好了你想要的类后,当你想使用它时,首先需要初始化一个ioc容器,

创建好之后,ioc容器中就会立刻加载相应类的实例化对象(加载的是单例bean不是多例bean)

//初始化ioc容器
 ApplicationContext context=new ClassPathXmlApplicationContext("加入之前配置的包含bean标签的xml文件");

然后调用ioc容器提供的getBean方法获取bean,也就是相应的类的实现对象,用对应的变量去接收它就可以用了。

 AccountDao accountDao = (AccountDao) context.getBean("accountDao");

这里的括号里的东西就是之前xml文件中bean标签内的id,通过id去调用相应的bean,再把他强转成相应的数据类型就可以用了。 

还有另外一种方法来获取bean,就是通过BeanFactory的方式创建对象,和前面的很像

 //通过BeanFactory的方式创建对象
 Resource resource=new ClassPathResource("相应的xml文件");
//创建spring bean工厂
   BeanFactory beanFactory=new XmlBeanFactory(resource);

再通过BeanFactory的对象去调用getBean方法获取具体的bean就行了。但是他和前面的有点不同,刚刚提到了ioc容器是在刚创建时就立马创建相应的bean,而Bean Factory是在准备获取bean时才创建(就是调用getBean时)。

前面的ApplicationContext间接的继承了BeanFactory,对BeanFactory的方法进行了扩展。

不过这个方法已经被标记为废弃了,只需要了解即可,现在主要还是用第一个方法。

下面来具体讲一下关于ApplicationContext的实现类

ClassPathXmlApplicationContext:加载类路径下面的spring配置文件

FileSystemXmlApplicationContext:加载磁盘绝对路径下面的配置文件

AnnotationConfigApplicationContext:用于直接环境,创建容器(后面再介绍)

接着我们来讲一下管理bean的其他方法

第二种

 <!--
       spring管理bean的第二种方式:基于实例化工厂管理bean
       factory-bean:引用的是工厂bean的id
       factory-method:引用的是工厂bean中的获取bean的方法名称
       -->
    <bean id="personFactory" class="com.xq.factory.PersonFactory"></bean>
    <bean id="personDao" class="com.xq.dao.impl.PersonDaoImpl" factory-bean="personFactory" factory-method="getPersonDao"></bean>
public class PersonFactory {
    //定义一个方法 方法的放回值就是需要被管理的bean类型
    public PersonDao getPersonDao() {
        return new PersonDaoImpl();
    }
}

factory-bean用于指定创建的工厂类的bean的id,factory-method用于指定工厂类中创建类的方法

调用的时候还是先加载xml文件,然后

​
​
 PersonDao personDao =(PersonDao) context.getBean("放入id");

​

​

第三种

 <!--
    spring中管理bean的第三种方式:使用静态实例化工厂管理bean
    -->
    <bean id="orderDaoFactory" class="com.xq.factory.OredrDaoFactory" factory-method="getOrder"></bean>
public class PersonFactory {
    //定义一个方法 方法的放回值就是需要被管理的bean类型
    public PersonDao getPersonDao() {
        return new PersonDaoImpl();
    }
}

调用跟上面查不多

​
​
   OrderDao orderDao=(OrderDao)context.getBean("bean中的id");

​

​

3.单例bean与多例bean

首先来讲一下什么叫做单例bean与多例bean

单例bean:在整个应用程序中,单例 Bean 只会存在一个实例。当应用程序启动时,单例 Bean 会被创建并初始化,并且在应用程序的生命周期内,这个 Bean 的实例只会被创建一次。

多例bean:多例 Bean 的创建由 Spring 容器负责,但在销毁时,Spring 容器不会像管理单例 Bean 那样进行统一管理。多例 Bean 在使用完后,如果没有其他对象引用它,会由 Java 的垃圾回收机制根据自身的算法决定是否回收该对象。这意味着多例 Bean 的生命周期管理主要依赖于 Java 的内存管理机制,而不是 Spring 容器的特定生命周期管理方法。

ioc容器默认创建的bean都是单例bean,

 UserDao userDao1=(UserDao)context.getBean("userDao");
        UserDao userDao2=(UserDao)context.getBean("userDao");
        System.out.println(userDao1==userDao2);

像这样,结果是true,构造函数只执行一次

如果像创建多例bean,可以在xml文件中的bean标签中加入scope=prototype。那么此时就会输出false,并且构造函数会执行两次。

4.bean的生命周期

单例对象

单例对象的生命周期和容器的生命周期是一致的。当容器创建时,对象就实例化好了。当容器还在的时 候,对象也就一直存在。当容器销毁,对象也就消亡

我们可以在bean标签中所指向的类中加入init(初始化)和destroy(销毁)方法,并在bean标签中加入init-method=“init”和destroy-method=“destroy”

只要ioc容器被创建init就会被自动执行,最后销毁执行

((ClassPathXmlApplicationContext)context).close();这个方法即可。

多例bean

多例就不用管这么多了,只需要保证我们创建的是多例,销毁时 Spring 容器不会管理,而是由 Java 的垃圾回收机制根据对象是否还有引用决定是否回收。

5.依赖注入

依赖注入是一种设计模式,也是 Spring 框架的核心功能之一。其本质是将对象所依赖的其他对象通过某种方式(如构造函数、方法参数、属性等)传递给对象,实现对象之间的解耦,提高代码的可维护性和可测试性。同时,依赖注入体现了控制反转的思想,将对象依赖关系的管理从对象内部转移到外部容器,由容器负责创建和注入依赖对象

使用setter方法进行依赖注入

但使用该方法的前提是被管的bean所属的类必须提供setter方法。

首先就是在要被调用的bean所属的类中写上各个成员变量的setter方法,然后在xml文件中的bean标签中配置。

public class User {
    private String username;
    private int age;
    private String address;
    private Car car;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", car=" + car +
                '}';
    }
}

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) context.getBean("user");
        System.out.println(user);
    }
}

xml相关配置如下

      <!--第一种:默认的使用set方法进行注入,使用set方法进行注入的前提是被管理的bean所属的类必须提供set方法
      property标签:完成bean的属性的注入
          name:描述的bean的属性名称
          value:描述bean的属性值(基本数据类型和字符串)
          ref:注入的是引用数据类型的值 引用的是另外一个bean的id
      -->
    <bean id="car" class="com.xq.pojo.Car">
        <property name="brand" value="宝马"></property>
        <property name="type" value="BMW540"></property>

    </bean>
    <bean id="user" class="com.xq.pojo.User">
        <property name="username" value="kunkun"></property>
        <property name="age" value="18"></property>
        <property name="address" value="CHINA"></property>
        <property name="car" ref="car"></property>
    </bean>

先看下面那个bean标签中的内容,他给user类中的每个成员变量都附上了初值,name就是成员变量的名字,value就是想要附的值。但是这里有一点要注意这里的car是一个引用变量,因为一个类中有很多个成员变量,所以不可能向上面一样直接用value来赋值所以又开了一个bean标签单独把car进行了初始化,这里就又点嵌套那味了,相当于用一个ref来将一个类嵌套在一个类中,这里的ref的值就是上面的id。

ref能够在不同的 Bean 之间建立起依赖关系,使得一个 Bean 可以使用另一个 Bean 的功能和属性。

来看输出结果

User{username='kunkun', age=18, address='CHINA', car=Car{brand='宝马', type='BMW540'}}

当然要看输出结果记得在目标类中加上toString方法。

使用构造函数实现依赖注入

第一步还是一样的,现在资源文件夹中的xml文件中导入相关bean标签,其实跟前面那个差不多,相关配置如下

 <!--
    spring的依赖注入的第二种方式:使用构造函数实现依赖注入
    constructor-arg:完成依赖注入 使用的是带参数的构造函数
    name:属性名称
    value:属性名称所属的值  必须是基本数据类型和字符串类型的值
    ref:引用数据类型的值
    -->
    <bean id="departement" class="com.xq.pojo.Department">
        <constructor-arg name="id" value="1"></constructor-arg>
        <constructor-arg name="name" value="技术部"></constructor-arg>
        <constructor-arg name="address" value="Newyork"></constructor-arg>
    </bean>
    <bean id="emp" class="com.xq.pojo.Emp">
        <constructor-arg name="id" value="1001"></constructor-arg>
        <constructor-arg name="name" value="kunkun"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
        <constructor-arg name="department" ref="departement"></constructor-arg>
    </bean>

也就是bean标签内的property标签换成了constructor标签,前面那个理解了这个自然是一个道理。但是有点要注意,就像前面一样,既然使用setter方法进行依赖注入需要bean所属的类需要setter方法,那么这个也是一样,需要类中有构造方法才能使用

其余代码如下

public class Emp {
    private int id;
    private String name;
    private int age;
    private Department department;
    public Emp() {}

    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", department=" + department +
                '}';
    }

    public Emp(int id, String name, int age, Department department) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.department = department;
    }
}

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
          Emp emp = (Emp)context.getBean("emp");
        System.out.println(emp);
    }
}

输出结果如下

Emp{id=1001, name='kunkun', age=18, department=Department{id=1, name='技术部', address='Newyork'}}

进行复杂数据类型的依赖注入

 上面只讲了简单数据类型,String类型和引用数据类型的依赖注入,下面就是复杂数据类性的依赖注入,例如各种集合,数组。

直接上代码:

public class Animal {
    private String[] strs;
    private List<String> list;
    private Set<String> set;
    private Map<String,String> map;
    private Properties pros;

    public String[] getStrs() {
        return strs;
    }

    public void setStrs(String[] strs) {
        this.strs = strs;
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public Set<String> getSet() {
        return set;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public Map<String, String> getMap() {
        return map;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public Properties getPros() {
        return pros;
    }

    public void setPros(Properties pros) {
        this.pros = pros;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "strs=" + Arrays.toString(strs) +
                ", list=" + list +
                ", set=" + set +
                ", map=" + map +
                ", pros=" + pros +
                '}';
    }
}

<!--
    进行复杂类型值的注入
    -->
    <bean id="animal" class="com.xq.pojo.Animal">
        <!--
        注入数组类型的值
        -->
        <property name="strs">
            <array>
                <value>str1</value>
                <value>str2</value>
                <value>str3</value>
            </array>
        </property>
        <!--
        注入list类型的值
        -->
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>
        <!--注入set-->
        <property name="set">
            <set>
                <value>s1</value>
                <value>s2</value>
                <value>s3</value>
            </set>
        </property>
        <!--
        注入Map
        -->
        <property name="map">
            <map>
                <entry key="k1" value="v1"></entry>
                <entry key="k2" value="v2"></entry>
                <entry key="k3" value="v3"></entry>
            </map>
        </property>
        <!--注入properties-->
        <property name="pros">
        <props>
        <prop key="p1">v1</prop>
        <prop key="p2">v2</prop>
        <prop key="p3">v3</prop>
        </props>
        </property>
    </bean>

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Animal animal=(Animal)context.getBean("animal");
        System.out.println(animal);

    }
}

还是差不多的,标明不同的name以及具体的数据类型就行了。

相关文章:

  • Java核心语法:从变量到控制流
  • 基于大模型的视神经脊髓炎手术全流程风险预测与诊疗方案研究
  • Android双亲委派
  • 模板注入(Twig)
  • 文件上传漏洞
  • 在CentOS系统上安装Conda的详细指南
  • Kubernetes教程(六)Harbor的安装和使用
  • 用DeepSeek学Android开发:Android初学者遇到的常见问题有哪些?如何解决?
  • react脚手架(creat-react-app)
  • FreeRTOS 任务间通信机制:队列、信号量、事件标志组详解与实验
  • RabbitMQ 高级特性:从 TTL 到消息分发的全面解析 (下)
  • Spring Boot静态资源访问顺序
  • redis有哪几种持久化方式
  • 通过数据库网格架构构建现代分布式数据系统
  • 顺序表与链表·续
  • Xshell链接Linux机器更换jdk版本
  • 基于架构的软件开发(ABSD)
  • C++11新特性1.原始字面量
  • 学之思社区版考试系统docker-compose部署
  • Selenium 中 ActionChains 支持的鼠标和键盘操作设置及最佳实践
  • 低价郑州网站建设/网站如何推广
  • 企业网站导航代码/制作一个网站需要多少费用
  • 网站建设seo优化/企业网站多少钱一年
  • 枣庄有做网站的吗/公司网站如何在百度上能搜索到
  • 聚美优品网站建设策划书/泰安百度推广代理商
  • 芜湖市建设工程网站维护公告/北京网站seo技术厂家