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
相关推荐
京东云开发者8 分钟前
本地缓存 Caffeine 中的时间轮(TimeWheel)是什么?
后端
半部论语11 分钟前
Spring **${}** vs **#{}** 语法全景图
java·数据库·spring boot·后端·spring
京东云开发者13 分钟前
缓存之美:万文详解 Caffeine 实现原理(上)
后端
sql2008help14 分钟前
数据分页异步后台导出excel
java·excel
知行合一。。。14 分钟前
Spring--04--2--AOP自定义注解,数据过滤处理
java·后端·spring
wuxuanok19 分钟前
八股——Kafka相关
java·笔记·后端·学习·kafka
啥都学点的程序员19 分钟前
python实现的websocket日志类
后端·python
京东云开发者20 分钟前
缓存之美:从根上理解 ConcurrentHashMap
后端
天天摸鱼的java工程师24 分钟前
MyBatis SQL 耗时记录的拦截器实战
java·后端·面试
oraen30 分钟前
kraft的设计与实现
java·kafka