首页 > 其他分享 >Spring之IoC

Spring之IoC

时间:2024-11-25 22:33:41浏览次数:6  
标签:IoC userDao Spring void import com public xu

1 IoC 控制反转

  • 控制反转是一种思想。
  • 控制反转,反转的是什么?
    • 将对象的创建权交出去,交给第三方容器负责。
    • 将对象和对象之间关系的维护权交出去,交给第三方容器负责。
  • 控制反转这种思想如何实现呢?
    • DI(Dependency Injection):依赖注入

2 依赖注入

Spring是通过依赖注入的方式来完成Bean管理的。
Bean管理指的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。

依赖注入:

  • 依赖指的是对象和对象之间的关联关系。
  • 注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。

依赖注入常见的实现方式包括两种:

  • 第一种:set注入
  • 第二种:构造注入

2.1 set注入

set注入是基于set方法实现的,底层会通过反射机制调用属性对应的set方法然后给属性赋值。这种方式要求必须对外提供属性的set方法。

通过一个例子来学习set注入

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xu</groupId>
    <artifactId>spring6-002-dependency-injection</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <!--spring context依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.0</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <!--log4j2的依赖-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.20.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j2-impl</artifactId>
            <version>2.20.0</version>
        </dependency>
    </dependencies>
</project>

UserService

package com.xu.service;

import com.xu.dao.UserDao;
import com.xu.dao.VipDao;

public class UserService {
    private UserDao userDao;
    private VipDao vipDao;

    public void save() {
        userDao.save();
        vipDao.save();
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void setVipDao(VipDao vipDao) {
        this.vipDao = vipDao;
    }
}

UserDao

package com.xu.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserDao {
    private static Logger LOGGER = LoggerFactory.getLogger(UserDao.class);

    public void save() {
        LOGGER.info("UserDao正在保存用户信息");
    }
}

VipDao

package com.xu.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class VipDao {
    private Logger LOGGER = LoggerFactory.getLogger(VipDao.class);

    public void save() {
        LOGGER.info("VipDao正在保存用户信息");
    }
}

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>

<configuration>
    <loggers>
        <root level="INFO">
            <appender-ref ref="log"/>
        </root>
    </loggers>

    <appenders>
        <console name="log" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
        </console>
    </appenders>
</configuration>

spring.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="userDao" class="com.xu.dao.UserDao"/>
    <bean id="vipDao" class="com.xu.dao.VipDao"/>

    <bean id="userService" class="com.xu.service.UserService">
        <property name="userDao" ref="userDao"/>
        <property name="vipDao" ref="vipDao"/>
    </bean>
</beans>

测试类

package com.xu.test;

import com.xu.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {
    @Test
    public void testIoC() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.save();
    }
}

运行结果:
image-20241125212340528

原理是什么?

set注入的核心实现原理:通过反射机制调用set方法来给属性赋值,让两个对象之间产生关系。

image-20241125214358725

举例验证

1.将成员属性的属性名改为userhaha和viphaha,然后保持set方法的方法名不变,测试这种情况下,程序应该可以正常运行。不会报错。

package com.xu.service;

import com.xu.dao.UserDao;
import com.xu.dao.VipDao;

public class UserService {
    private UserDao userhaha;
    private VipDao viphaha;

    public void save() {
        userhaha.save();
        viphaha.save();
    }

    public void setUserDao(UserDao userDao) {
        this.userhaha = userDao;
    }

    public void setVipDao(VipDao vipDao) {
        this.viphaha = vipDao;
    }
}
<?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">
    <bean id="userDao" class="com.xu.dao.UserDao"/>
    <bean id="vipDao" class="com.xu.dao.VipDao"/>

    <bean id="userService" class="com.xu.service.UserService">
        <property name="userDao" ref="userDao"/>
        <property name="vipDao" ref="vipDao"/>
    </bean>
</beans>

运行结果:成功

image-20241125215109108

2.保持成员属性的属性名不变,将set方法的方法名改为setUserDaoHaHa和setVipDaoHaHa,测试这种情况下,程序应该会报错。

package com.xu.service;

import com.xu.dao.UserDao;
import com.xu.dao.VipDao;

public class UserService {
    private UserDao userDao;
    private VipDao vipDao;

    public void save() {
        userDao.save();
        vipDao.save();
    }

    public void setUserDaoHaHa(UserDao userDao) {
        this.userDao = userDao;
    }

    public void setVipDaoHaHa(VipDao vipDao) {
        this.vipDao = vipDao;
    }
}

如果property的name还是传的userDao和vipDao就会报错

<?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">
    <bean id="userDao" class="com.xu.dao.UserDao"/>
    <bean id="vipDao" class="com.xu.dao.VipDao"/>

    <bean id="userService" class="com.xu.service.UserService">
        <property name="userDao" ref="userDao"/>
        <property name="vipDao" ref="vipDao"/>
    </bean>
</beans>

image-20241125215334833

将property的name改为userDaoHaHa和vipDaoHaHa就成功了

<?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">
    <bean id="userDao" class="com.xu.dao.UserDao"/>
    <bean id="vipDao" class="com.xu.dao.VipDao"/>

    <bean id="userService" class="com.xu.service.UserService">
        <property name="userDaoHaHa" ref="userDao"/>
        <property name="vipDaoHaHa" ref="vipDao"/>
    </bean>
</beans>

image-20241125215449615

2.2 构造注入

原理:通过调用构造方法来给属性赋值。

使用下标注入

package com.xu.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OrderDao {
    private static Logger LOGGER = LoggerFactory.getLogger(OrderDao.class);

    public void orderService() {
        LOGGER.info("服务已预约~");
    }
}
package com.xu.service;

import com.xu.dao.OrderDao;

public class OrderService {
    private OrderDao orderDao;

    public OrderService(OrderDao orderDao) {
        this.orderDao = orderDao;
    }

    public void order() {
        orderDao.orderService();
    }
}
<bean id="orderDao" class="com.xu.dao.OrderDao" />

<bean id="orderService" class="com.xu.service.OrderService">
    <!--index="0"表示构造方法的第一个参数,将orderDao对象传递给构造方法的第一个参数。-->
    <constructor-arg index="0" ref="orderDao"/>
    <!-- 如果有多个构造方法参数,则继续加index="1" -->
    <!-- <constructor-arg index="1" ref="orderDao"/>-->
</bean>
@Test
public void testConstructorDI() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
    orderService.order();
}

运行结果如下:
image-20241125220935567

使用构造方法参数名注入

package com.xu.service;

import com.xu.dao.UserDao;
import com.xu.dao.VipDao;

public class UserService2 {
    private UserDao userDao;
    private VipDao vipDao;

    public UserService2(UserDao userDao, VipDao vipDao) {
        this.userDao = userDao;
        this.vipDao = vipDao;
    }

    public void save() {
        userDao.save();
        vipDao.save();
    }
}
@Test
public void testConstructorDIByName() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    UserService2 userService2 = applicationContext.getBean("userService", UserService2.class);
    userService2.save();
}
<?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">
    <bean id="userDao" class="com.xu.dao.UserDao"/>
    <bean id="vipDao" class="com.xu.dao.VipDao"/>

    <bean id="userService" class="com.xu.service.UserService2">
        <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="vipDao" ref="vipDao"/>
    </bean>
</beans>

image-20241125221827573

即不指定下标,也不指定参数名,让Spring自行判断

<bean id="userServiceBean" class="com.xu.service.UserService2">
    <constructor-arg ref="userDao"/>
    <constructor-arg ref="vipDao"/>
</bean>
@Test
public void testConstructorDIWithNothing() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    UserService2 userService = applicationContext.getBean("userServiceBean", UserService2.class);
    userService.save();
}

image-20241125222149379

3 set注入专题

3.1 注入外部Bean

<?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">

    <bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>

    <bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
        <property name="userDao" ref="userDaoBean"/> <!-- 这个就叫做注入外部bean -->
    </bean>

</beans>

外部Bean的特点:bean定义在外面,在property标签中使用ref属性进行注入。这种方式比较常用。

3.2 注入内部Bean

内部Bean的方式:在bean标签中嵌套bean标签。

<?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">

    <bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
        <property name="userDao">
            <bean class="com.powernode.spring6.dao.UserDao"/>
        </property>
    </bean>

</beans>

3.3 注入简单类型

package com.xu.entity;

public class User {
    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 "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

第二步:编写spring配置文件:spring-simple-di.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="com.xu.entity.User">
        <property name="name" value="xu"/>
        <property name="age" value="22"/>
    </bean>
</beans>

第三步:编写测试程序

@Test
public void testSimpleValue() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-simple-di.xml");
    User user = applicationContext.getBean("user", User.class);
    System.out.println(user);
}

第四步:运行测试程序
image-20241125222754403

标签:IoC,userDao,Spring,void,import,com,public,xu
From: https://www.cnblogs.com/growingbambi/p/18568949

相关文章

  • 基于Java+SpringBoot+Mysql在线简单拍卖竞价拍卖竞拍系统功能设计与实现七
    一、前言介绍:免费学习:猿来入此1.1项目摘要主要源于互联网技术的快速发展和电子商务的普及。随着网络技术的不断进步,人们越来越依赖于互联网进行购物、交易和沟通。电子商务的兴起为在线拍卖提供了广阔的市场和便利的条件。在线拍卖系统通过搭建一个虚拟的拍卖平台,将传统......
  • 基于Java+SpringBoot+Mysql在线简单拍卖竞价拍卖竞拍系统功能设计与实现八
    一、前言介绍:免费学习:猿来入此1.1项目摘要主要源于互联网技术的快速发展和电子商务的普及。随着网络技术的不断进步,人们越来越依赖于互联网进行购物、交易和沟通。电子商务的兴起为在线拍卖提供了广阔的市场和便利的条件。在线拍卖系统通过搭建一个虚拟的拍卖平台,将传统......
  • SpringCloud入门(十二)全局过滤器和跨域
    一、全局过滤器全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义,处理逻辑是固定的,如果我们希望拦截请求,做自己的业务逻辑则没办法实现。而GlobalFilter的逻辑需要自己写代码实现。定义方式是实现Glob......
  • Spring 中的 @Value 注解
    Spring中的@Value注解引言:Spring与依赖注入在Java开发中,Spring框架是一个不可或缺的工具,它通过依赖注入(DI)和面向切面编程(AOP)等技术,简化了企业级应用的开发。依赖注入是Spring的核心概念之一,它允许开发者将对象的依赖关系交由Spring容器管理,而不是在代码中硬编......
  • SpringCloud入门(九)Feign实战应用和性能优化
    一、Feign实战应用 Feign的客户端与服务提供者的controller代码非常相似:有没有一种办法简化这种重复的代码编写呢?方式一:继承优点:简单。实现了代码共享。缺点:服务提供方、服务消费方紧耦合。参数列表中的注解映射并不会继承,因此Controller中必须再次声明方法、参数列表、......
  • SpringCloud入门(十)统一网关Gateway
    一、网关的作用SpringCloudGateway是SpringCloud的一个全新项目,该项目是基于Spring5.0,SpringBoot2.0和ProjectReactor等响应式编程和事件流技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的API路由管理方式。网关架构图: 网关......
  • SpringCloud入门(七)Feign声明式远程调用
    利用RestTemplate发起远程调用的代码,存在下面的问题:代码可读性差,编程体验不统一。参数复杂URL难以维护。Feign是一个声明式的http客户端,官方地址:https://spring.io/projects/spring-cloud-openfeign 。其作用是帮助我们优雅的实现http请求的发送。一、使用Feign实......
  • SpringCloud入门(八)Feign自定义配置
    一、Feign自定义配置Feign可以支持很多的自定义配置,如下表所示:-类型:feign.Logger.Level作用:修改日志级别说明:包含四种不同的级别:NONE、BASIC、HEADERS、FULL-类型:feign.codec.Decoder作用:响应结果的解析器说明:http远程调用的结果......
  • JavaWeb——SpringBoot原理
    10.1.配置优先级10.1.1.配置文件properties>yml(推荐)>yaml10.1.2.Java系统属性、命令行参数命令行参数>Java系统属性>配置文件10.2.Bean管理10.2.1.手动获取beanApplicationContext,IOC容器对象10.2.2.bean作用域10.2.3.第三方bean自定义的......
  • SpringAop--Java面试题
    目录Spring的事务隔离级别?Spring的事务传播行为?1>概念2>事务传播的配置什么是AoP?AoP与ooP有何区别?1>Aop的概念2>Aop和OOp的区别什么是连接点、切点和增强(或通知)?连接点切点增强什么是织入?有哪些织入方式?1>织入概念2>织入方式什么是切面?SpringAoP如何定义一个切面?1>切......