Spring IoC容器与Bean管理

代码结构

Text 复制代码
spring01/
├── pom.xml
├── spring01.iml
└── src/
    ├── main/
    │   ├── java/
    │   │   └── com/
    │   │       └── demo/
    │   │           ├── bean/
    │   │           │   ├── Demo.java
    │   │           │   ├── Emp1.java
    │   │           │   ├── Emp2.java
    │   │           │   └── User.java
    │   │           ├── dao/
    │   │           │   ├── UserDao.java
    │   │           │   └── impl/
    │   │           │       ├── MysqlUserDaoImpl.java
    │   │           │       └── OracleUserDaoImpl.java
    │   │           ├── factory/
    │   │           │   ├── Emp1Factory.java
    │   │           │   ├── Emp2Factory.java
    │   │           │   └── UserDaoFactory.java
    │   │           ├── service/
    │   │           │   ├── UserService.java
    │   │           │   └── impl/
    │   │           │       └── UserServiceImpl.java
    │   │           └── test/
    │   │               └── UserTest.java
    │   └── resources/
    │       ├── UserDao.properties
    │       ├── applicationContext-实例工厂创建Bean.xml
    │       ├── applicationContext-普通构建方法创建Bean.xml
    │       ├── applicationContext-静态工厂创建Bean.xml
    │       ├── applicationContext.xml
    │       └── logback.xml
    └── test/
		└── java/
		    └── com/
		        └── demo/
		            ├── LoggerTest.java
		            ├── TestDemo.java
		            └── UserTest.java

该项目是一个Spring框架练习项目,主要围绕以下核心目标进行实践:

一、核心技术练习

  1. Spring IoC容器与Bean管理

    • 实现了多种Bean创建方式(普通构造方法、静态工厂、实例工厂)
    • 对应配置文件:applicationContext-*.xml系列文件
  2. 设计模式应用

    • 工厂模式:通过Emp1FactoryEmp2Factory等类实现对象创建封装
    • 接口编程:UserDao接口+Mysql/Oracle多实现类
  3. 分层架构实践

    复制代码
    com.demo
    ├── bean      // 数据模型层(User.java等实体类)
    ├── dao       // 数据访问层(数据库操作接口及实现)
    ├── service   // 业务逻辑层(服务接口及实现)
    └── factory   // 对象工厂层(创建Bean的工厂类)

二、功能模块说明

  • 数据访问 :通过UserDao及实现类操作数据库,支持多数据库类型(MySQL/Oracle)
  • 依赖注入:使用Spring容器管理对象依赖关系
  • 日志系统 :集成logback日志框架(logback.xml配置)
  • 配置管理 :通过UserDao.properties实现配置外部化

三、测试覆盖

  • 单元测试LoggerTest(日志测试)、UserTest(用户功能测试)等测试类
  • 测试规范:遵循与主代码相同的包结构,确保测试代码可维护性

四、项目特点

  • 性质:通过多种配置文件和工厂类展示不同实现方式
  • 结构清晰:严格遵循Maven项目规范和分层架构设计
  • 可扩展性:通过接口和工厂模式预留功能扩展点

该项目适合初学者理解Spring核心概念、设计模式应用及企业级项目分层架构思想。

实体类 bean

java 复制代码
package com.demo.bean;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class Demo {
    private List<String> list;
    private Set<String> set;
    private Map<String,String> map;
    private Properties properties;

    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 getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}
package com.demo.bean;

public class Emp1 {
    public  void update1(){
        System.out.println("Emp1的update1()方法被调用。。。  。。。");
    }
}
package com.demo.bean;

public class Emp2 {
    public  void update2(){
        System.out.println("Emp2的update2()方法被调用。。。  。。。");
    }
}
package com.demo.bean;

public class User {
    private  Integer userId;
    private  String username;
    private  String password;

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUsername() {
        return username;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

dao层

java 复制代码
import com.demo.bean.User;

public interface UserDao {
    public  boolean updateUser(User user);
}

import com.demo.bean.User;
import com.demo.dao.UserDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MysqlUserDaoImpl implements UserDao {
    @Override
    public boolean updateUser(User user) {
        Logger logger = LoggerFactory.getLogger(MysqlUserDaoImpl.class);
        logger.info("Mysql正在进行修改操作:updateUser();");
        return true;
    }
}



import com.demo.bean.User;
import com.demo.dao.UserDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OracleUserDaoImpl implements UserDao {
    @Override
    public boolean updateUser(User user) {
        Logger logger = LoggerFactory.getLogger(OracleUserDaoImpl.class);
        logger.info("Oracle正在进行修改操作:updateUser();");
        return true;
    }
}

简单工厂模式

java 复制代码
import com.demo.bean.Emp1;

public class Emp1Factory {
public static Emp1 getInstance(){
    return new Emp1();
}
}

package com.demo.factory;

import com.demo.bean.Emp2;

public class Emp2Factory {
    public Emp2 getInstance() {
        return new Emp2();
    }
}


package com.demo.factory;

import com.demo.dao.UserDao;

import java.io.InputStream;
import java.util.Properties;

public class UserDaoFactory {

    public  UserDao getInstance() {
        UserDao userDao = null;
        try {
            //读取属性文件
            Properties properties = new Properties();
            InputStream in = UserDaoFactory.class.getClassLoader().getResourceAsStream("UserDao.properties");
            properties.load(in);
            //通过key获取全名字符串
            String userDaoFullName = properties.getProperty("userDao");
            //通过反射获取类的实例对象
            userDao = (UserDao) Class.forName(userDaoFullName).newInstance();
        } catch (
                Exception e) {
            e.printStackTrace();
        }
        return userDao;
    }
}

service层

java 复制代码
import com.demo.bean.User;

public interface UserService {
   public boolean updateUser(User user);
}

package com.demo.service.impl;

import com.demo.bean.User;
import com.demo.dao.UserDao;
import com.demo.factory.UserDaoFactory;
import com.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 1.UserDao 的实现类不由UserServiceImpl来决定,而是由UserDaoFactory来决定<第一种>
 * 2.控制权从UserServiceImpl转移到了UserDaoFactory,这就是控制反转IOC/DI
 */
@Service
public class UserServiceImpl  implements UserService{
   /** 
   <第一种>
   UserDaoFactory userDaoFactory=new UserDaoFactory();
    UserDao userDao=userDaoFactory.getInstance();*/
    @Autowired
	private   UserDao userDao;
	
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    // private UserDao userDao=new UserDaoFactory.getInstance();//报错
   // private UserDao userDao=new MysqlUserDaoImpl();
   //private UserDao userDao=new OracleUserDaoImpl();

    @Override
    public boolean updateUser(User user) {
        return userDao.updateUser(user);
    }
}

测试

日志测试
java 复制代码
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggerTest {
    @Test
    public void loggerTest() {
        //System.out.println(LoggerFactory.getLogger("hello"));

        Logger logger = LoggerFactory.getLogger(LoggerTest.class);

        //slf4j日志的级别
        logger.trace("trace");
        logger.debug("debug");
        logger.info("info");
        logger.warn("warn");
        logger.error("error");

        //拼接
        logger.info("Welcome to {} {} ", "www.51zxw.net", "go!");
    }

}
测试 applicationContext.xml 配置文件的配置
java 复制代码
package com.demo;

import com.demo.bean.Demo;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.*;

public class TestDemo {
    Logger logger = LoggerFactory.getLogger(LoggerTest.class);

    @Test
    public void testDemo() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Demo demo = (Demo) context.getBean("demo");
        List<String> list = demo.getList();
        logger.info("list----------------------");
        for (String s : list) {
            logger.info(s);
        }
        logger.info("set----------------------");
        Set<String> set = demo.getSet();
        for (String s : set) {
            logger.info(s);
        }
        logger.info("map----------------------");
        Map<String, String> map = demo.getMap();
        Set<String> keySet = map.keySet();
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            String value = map.get(key);
            logger.info(key + "  " + value);
        }
        logger.info("properties----------------------");
        Properties properties = demo.getProperties();
        String userId = properties.getProperty("userId");
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");
        logger.info(userId);
        logger.info(username);
        logger.info(password);
    }
}
测试其他集中配置文件管理Bean
java 复制代码
package com.demo;

import com.demo.bean.Emp1;
import com.demo.bean.Emp2;
import com.demo.bean.User;
import com.demo.dao.UserDao;
import com.demo.service.UserService;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 1.从SpringIOC容器工厂中获取一个User对象
 * a。获取工厂BeanFactory
 * b。getBean()返回对象
 * 2.ApplicationContext是BeanFactory的子接口(实际上也是工厂)
 */
public class UserTest {
    Logger logger = LoggerFactory.getLogger(LoggerTest.class);

    /**
     * 测试普通构造方法创建的Bean
     */
    @Test
    public void userTest() {
        //获取BeanFactory的子接口,它是用来获得配置在SpringIOC容器的对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从SpringIOC容器工厂中获取一个User对象
        User user = (User) context.getBean("user");
        if (null != user) {
            logger.info(user.toString());
        }
    }

    /**
     * 测试普通构造方法创建的Bean
     */
    @Test
    public void userDaoTest() {
        //获取BeanFactory的子接口,它是用来获得配置在SpringIOC容器的对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-实例工厂创建Bean.xml");
        //从SpringIOC容器工厂中获取一个User对象
        UserDao userDao = (UserDao) context.getBean("userDao");
        if (null != userDao) {
            userDao.updateUser(null);
        }
    }

    /**
     * 静态工厂创建Bean
     */
    @Test
    public void emp1Test() {
        //获取BeanFactory的子接口,它是用来获得配置在SpringIOC容器的对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-实例工厂创建Bean.xml");
        //从SpringIOC容器工厂中获取一个User对象
        Emp1 emp1 = (Emp1) context.getBean("emp1");
        if (null != emp1) {
            emp1.update1();
        }
    }

    /**
     * 实例工厂创建Bean
     */
    @Test
    public void emp2Test() {
        //获取BeanFactory的子接口,它是用来获得配置在SpringIOC容器的对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-实例工厂创建Bean.xml");
        //从SpringIOC容器工厂中获取一个User对象
        Emp2 emp2 = (Emp2) context.getBean("emp2");
        if (null != emp2) {
            emp2.update2();
        }
    }

    @Test
    public void userServiceTest() {
        //获取BeanFactory的子接口,它是用来获得配置在SpringIOC容器的对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //从SpringIOC容器工厂中获取一个User对象
        UserService userService = (UserService) context.getBean("userService");
        if (null != userService) {
            userService.updateUser(null);
        }
    }
}
测试第一种被UserDaoFactory来决定实现的方式

要解开注解,UserServiceImpl代码改为

java 复制代码
    UserDaoFactory userDaoFactory=new UserDaoFactory();
    UserDao userDao=userDaoFactory.getInstance();
//    @Autowired
//    private  UserDao userDao;
// 其余不变
java 复制代码
package com.demo.test;

import com.demo.bean.User;
import com.demo.service.UserService;
import com.demo.service.impl.UserServiceImpl;

public class UserTest {
    public static void main(String[] args) {
        UserService userService=new UserServiceImpl();
        User user=new User();
        userService.updateUser(user);
    }
}

配置文件

applicationContext.xml

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.demo.bean.User">
        <!--  为对象注入属性值   -->
        <property name="userId" value="1"></property>
        <property name="username" value="张三"></property>
        <property name="password" value="123456"></property>
    </bean>
    <!-- 1.创建属性对象MysqlUserDaoImpl(如果是Besn类型)
      a.必须添加setter()方法注入属性;
      b.通过构造方法注入属性
      2.创建userService
      -->
    <bean id="userDao" class="com.demo.dao.impl.MysqlUserDaoImpl"></bean>
    <bean id="userService" class="com.demo.service.impl.UserServiceImpl">
        <!--    ref是通过引用userDao,然后找到实现类    -->
        <property name="userDao" ref="userDao"></property>
    </bean>
    <!--
    集合属性的注入:
    list:添加list节点,然后如果集合中的数据是引用数据类型需要使用ref节点,如果是基本数据类型用value
    set:添加set节点,然后如果集合中的数据是引用数据类型需要使用ref节点,如果是基本数据类型用value
    map:添加map节点,由于map中储存的是key和value键值对,需要添加一个entry节点
    对应key,如果数据是引用数据类型需要使用ref节点,如果是基本数据类型用value
    对应value,如果数据是引用数据类型需要使用ref节点,如果是基本数据类型用value
    properties:添加props节点,然后在添加prop
    -->

    <bean id="demo" class="com.demo.bean.Demo">
        <property name="list">
            <list>
                <value>乔丹</value>
                <value>科比</value>

                <!--<bean>ref的配置</bean>-->
                <!--                <ref>如果是类类型,或者引用数据类型,需要ref</ref>-->
            </list>
        </property>
        <property name="set">
            <set>
                <value>姚明</value>
                <value>易建联</value>
                <value>王致和</value>
            </set>
        </property>

        <property name="map">
            <map>
                <entry>
                    <key>
                        <value>001</value>
                    </key>
                    <value>篮球</value>
                </entry>
                <entry>
                    <key>
                        <value>002</value>
                    </key>
                    <value>足球</value>
                </entry>
                <entry>
                    <key>
                        <value>003</value>
                    </key>
                    <value>乒乓球</value>
                </entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="userId">1</prop>
                <prop key="username">test</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>
</beans>

applicationContext-实例工厂创建Bean.xml

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
    1.创建Emp2
    2.创建Emp2Factory静态工厂
    3.编写配置文件,注意和普通工厂对比,多两个属性配置factory-method="静态方法名"
    factory-bean属性的配置


    总结:相比普通构造方法创建Bean而言稍微麻烦一些,所以很少用
    -->
    <bean id="emp2Factory" class="com.demo.factory.Emp2Factory"></bean>
    <bean id="emp2" factory-bean="emp2Factory" factory-method="getInstance"></bean>
</beans>

applicationContext-普通构建方法创建Bean.xml

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">
    <!--    Spring容器-->
    <!--采用普通的构造方法来创建Bean-->
    <bean id="userService" class="com.demo.service.impl.UserServiceImpl"></bean>
    <bean id="userDao" class="com.demo.dao.impl.MysqlUserDaoImpl"></bean>
    <!-- 采用普通的构建方法创建User-->
    <bean id="user" class="com.demo.bean.User"></bean>

</beans>

applicationContext-静态工厂创建Bean.xml

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
1.创建Emp1
2.创建Emp1Factory静态工厂
3.编写配置文件,注意和普通工厂对比,多一个属性配置factory-method="静态方法名"

总结:相比普通构造方法创建Bean而言稍微麻烦一些,所以很少用
-->
<bean id="emp1" class="com.demo.factory.Emp1Factory" factory-method="getInstance"></bean>

</beans>

logback.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--输出日志到控制台 appender追加-->
    <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
        <!--负责把事件转成字符串,格式化日志信息的输出-->
        <layout>
            <pattern>
                <!--%p是日志优先级%d是日期,%msg是日志消息%n换行-->
                [%p]%d-%msg%n
            </pattern>
        </layout>
    </appender>
    <appender name="fileLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <onMatch>DENY</onMatch>
        </filter>
        <encoder>
            <pattern>
                [%p]%d-%msg%n
            </pattern>
        </encoder>
        <!-- 指定文件的输出位置-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>

            </fileNamePattern>
        </rollingPolicy>
    </appender>
<!-- 控制台可以输出的级别   -->
    <root level="info">
        <appender-ref ref="consoleLog"></appender-ref>
        <appender-ref ref="fileLog"></appender-ref>
    </root>
</configuration>

UserDao.properties

properties 复制代码
userDao=com.demo.dao.impl.OracleUserDaoImpl
相关推荐
CS Beginner6 分钟前
【搭建】个人博客网站的搭建
java·前端·学习·servlet·log4j·mybatis
JavaTree201742 分钟前
【Spring Boot】Spring Boot解决循环依赖
java·spring boot·后端
lang201509281 小时前
Maven 五分钟入门
java·maven
cj6341181501 小时前
SpringBoot配置Redis
java·后端
用坏多个鼠标1 小时前
Nacos和Nginx集群,项目启动失败问题
java·开发语言
TangKenny2 小时前
基于EasyExcel的动态列映射读取方案
java·easyexcel
安冬的码畜日常2 小时前
【JUnit实战3_19】第十章:用 Maven 3 运行 JUnit 测试(下)
java·测试工具·junit·单元测试·maven·junit5
lemon_sjdk2 小时前
软件开发模式架构选择
java·架构·软件开发·前后端分离
董广明2 小时前
单元测试(JUnit、Mockito、PowerMock )
java·经验分享·junit·单元测试
Lisonseekpan2 小时前
Java Stream 流式编程
java·后端