Spring框架 - IoC容器

Spring - IoC的简单配置示例

通过上一篇的文章可以初步了解了spring框架的相关概念。
现在我们完成一个简单的登录注册案例。

项目结构如下
在这里插入图片描述

pom.xml配置

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.0.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.20</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.48</version>
    </dependency>

    <dependency>
      <groupId>commons-dbutils</groupId>
      <artifactId>commons-dbutils</artifactId>
      <version>1.7</version>
    </dependency>


  </dependencies>

database.properties配置

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/user
jdbc.username=root
jdbc.password=123456

版本一 xml配置版

applicationContext.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="configurer" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
        <property name="location" value="database.properties"/>
    </bean>

    <!--德鲁伊连接池配置-->
    <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--queryRunner配置-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
        <!--构造方法:public QueryRunner(DataSource ds) {super(ds);}-->
        <constructor-arg name="ds" ref="datasource"/>
    </bean>


    <bean id="menuController" class="com.alter.spring.controller.MenuController">
        <property name="loginController" ref="loginController"/>
        <property name="registerController" ref="registerController"/>
    </bean>

    <bean id="loginController" class="com.alter.spring.controller.LoginController">
        <property name="userService" ref="userService"/>
    </bean>


    <bean id="userService" class="com.alter.spring.service.impl.UserServiceImpl">
        <property name="userDAO" ref="userDAO"/>
    </bean>

    <bean id="userDAO" class="com.alter.spring.dao.impl.UserDAOImpl">
        <property name="queryRunner" ref="queryRunner"/>
    </bean>


    <bean id="registerController" class="com.alter.spring.controller.RegisterController">
        <property name="userService" ref="userService"/>
    </bean>


</beans>

MenuController

package com.alter.spring.controller;

import java.util.Scanner;

public class MenuController {
    private LoginController loginController;
    private RegisterController registerController;

    public void mainUI(){

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入选项");
        System.out.println("1.登录;2.注册;3.退出");

        String option = sc.next();

        if(option.equals("1")) {
            //登录方法
            loginController.login();
        }else if(option.equals("2")) {
            //注册方法
            registerController.register();
        }else if(option.equals("3")) {
            //退出方法
			
        }else{
            System.out.println("输入错误,请重新输入");

        }
    }

    public void setLoginController(LoginController loginController) {
        this.loginController = loginController;
    }

    public void setRegisterController(RegisterController registerController) {
        this.registerController = registerController;
    }
}

LoginController

package com.alter.spring.controller;

import com.alter.spring.service.UserService;
import com.alter.spring.model.User;

import java.util.Scanner;

public class LoginController {
    private UserService userService;

    public void login(){

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = sc.next();

        //查询数据库有没有这个用户
        User queryUsername = userService.queryUsername(username);

        if(queryUsername!=null){
            System.out.println("请输入密码:");
            String password = sc.next();
            //查询数据库
            User user = userService.login(username, password);
            //判断
            if(user != null){
                System.out.println("欢迎"+user.getUsername()+"登录");

            }else{
                System.out.println("用户名或密码错误。请重新输入:");
                login();
            }
        }else {
            System.out.println("用户不存在,请重新输入");
            login();
        }

    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

RegisterController

package com.alter.spring.controller;

import com.alter.spring.model.User;
import com.alter.spring.service.UserService;

import java.util.Scanner;

public class RegisterController {
    private UserService userService;

    public void register(){
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = sc.next();

        //查询用户名是否存在
        User user = userService.queryUsername(username);
        if(user==null){
            System.out.println("请输入密码:");
            String password = sc.next();
            //调用Service保存数据
            userService.register(username,password);
            System.out.println("注册成功!");
        }else{
            System.out.println("用户已存在,请重新注册。");
            register();
        }
    }
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

Service实现

package com.alter.spring.service.impl;

import com.alter.spring.dao.UserDAO;
import com.alter.spring.service.UserService;
import com.alter.spring.model.User;

public class UserServiceImpl implements UserService {

    private UserDAO userDAO;

    @Override
    public User login(String username, String password) {

        return userDAO.login(username,password);
    }

    @Override
    public User queryUsername(String username) {
        return userDAO.queryUsername(username);
    }

    @Override
    public void register(String username,String password) {
        userDAO.register(username,password);
    }

    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }
}
UserDAO实现
package com.alter.spring.dao.impl;

import com.alter.spring.dao.UserDAO;
import com.alter.spring.model.User;
import org.apache.commons.dbutils.BasicRowProcessor;
import org.apache.commons.dbutils.GenerousBeanProcessor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import java.sql.SQLException;

public class UserDAOImpl implements UserDAO {
    
    private  QueryRunner queryRunner;

    @Override
    public User login(String username, String password) {
        // 编写sql语句
        String sql = "select * from user where username =? and password =?";
        // 执行查询
        try {
            return queryRunner.query(sql, new BeanHandler<User>(User.class,new BasicRowProcessor(new GenerousBeanProcessor())), username, password);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public User queryUsername(String username) {
        // 编写sql语句
        String sql = "select * from user where username =?";
        // 执行查询
        try {
            return queryRunner.query(sql, new BeanHandler<User>(User.class,new BasicRowProcessor(new GenerousBeanProcessor())), username);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void register(String username, String password) {
        // 编写sql语句
        String sql = "insert into user(username,password) values(?,?)";
        try {
            queryRunner.update(sql, username,password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    public void setQueryRunner(QueryRunner queryRunner) {
        this.queryRunner = queryRunner;
    }
}

版本二 注解式IoC

我们发现用xml配置很多重复代码,并且需要对整个相关目结构非常清楚。因为引入了注解来简化xml代码。
具体的操作为用注解来代替xml中的bean

在Controller层的类上加上@Controller注解,Service实现类的加上@Service注解,在DAO层的实现类上加上@Repository注解,其他普通类加上@Component,并且在类的属性声明上加上@Autowired来自动注入依赖,以此来让框架识别。

xml

删除一般的类

<beans>
    <!--扫描含有注解类-->
    <context:component-scan base-package="com.alter.spring"/>

    <!--读取配置文件-->
    <bean id="configurer" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
        <property name="location" value="database.properties"/>
    </bean>

    <!--德鲁伊连接池配置-->
    <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--queryRunner配置-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
        <!--构造方法:public QueryRunner(DataSource ds) {super(ds);}-->
        <constructor-arg name="ds" ref="datasource"/>
    </bean>
</beans>

Controller层

以loginController为例:

@Controller //在类的声明加上@Controller注解
public class LoginController {
    @Autowired   //在属性的声明上加上@Autowired注解,自动注入
    private UserService userService;
    ...
}

Service实现类

@Service  //在类的声明加上@Service注解
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDAO userDAO;
    ...
}

DAO层实现类

@Repository   //在类的声明加上 @Repository 注解
public class UserDAOImpl implements UserDAO {
    @Autowired
    private  QueryRunner queryRunner;
    ...
}

版本三 Java配置式的IoC

注解版减少了一些不必要的xml配置,但是还是觉得xml配置比较麻烦,有没有不需要xml的?答案是肯定的,下面我们讲一讲不需要xml怎么配置。

在此我们需要引入几个注解

  • @Bean 标记某个方法返回值为spring的bean,方法参数为依赖注入的请求。
  • @Configuration 标记一个类为配置类

具体实现步骤:
1、新建一个java类作为配置类,加上@Configuration注解让Spring识别;
2、在配置类创建方法,返回值为bean的实例,添加@Bean注解;

此时,其他类是没有任何注解的。

创建配置类

因此我们创建一个配置类AppConfig。


@Configuration	//声明这个类是配置文件
@PropertySource("database.properties")	//读取properties文件 
public class AppConfig {
	//声明这些jdbc属性,用于链接数据库
    @Value("${jdbc.driverClass}")	//SpEL表达式,可以读取properties文件的指定属性值
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;


    @Bean	//添加@bean注解,说明这个方法返回值是一个bean实例
    public LoginController loginController(){
    	//创建一个对象
        LoginController loginController = new LoginController();
        //可以通过调用本类的方法来设置实例的属性
        loginController.setUserService(userService());
        //返回这个对象
        return loginController;
    }

    @Bean
    public MenuController menuController(LoginController loginController){
        MenuController menuController = new MenuController();
        menuController.setRegisterController(registerController());
		//也可以通过在方法参数中声明容器中以存在的bean,再在方法内部使用
        menuController.setLoginController(loginController);
        return menuController;
    }

    @Bean
    public RegisterController registerController(){
        RegisterController registerController = new RegisterController();
        registerController.setUserService(userService());
        return registerController;
    }

    @Bean
    public UserService userService(){
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDAO(userDAO());
        return userService;
    }

    @Bean
    public UserDAO userDAO(){
        UserDAOImpl userDAO = new UserDAOImpl();
        userDAO.setQueryRunner(queryRunner(druidDataSource()));
        return userDAO;
    }

    @Bean(destroyMethod = "close")	//destroyMethod 表示容器销毁时,调用德鲁伊连接池的close方法。
    public DruidDataSource druidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driverClassName);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }
    
    @Bean
    public QueryRunner queryRunner(DataSource dataSource){
        return new QueryRunner(dataSource);
    }
}

测试类

注意此时测试类得到容器的方法改变了,因为不再需要xml文件。

public class App {

    public static void main(String[] args) {
    	//读取配置类,创建容器
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
		//从容器中取得bean实例,并调用方法
        MenuController menuController = ac.getBean("menuController",MenuController.class);
        menuController.mainUI();
    }
}

版本四 扫描版

虽然不用xml,但是bean配置也是相当麻烦。那么怎么简化呢?
那就是采用注解来简化。
在此引入注解:
@ComponentScan 打开包扫描功能
实现步骤:
1、在类和属性上添加注解,和版本二的注解式添加方式一样;
2、在配置类上添加属性@ComponentScan 打开包扫描功能,并且指定扫描的包路径;


@Configuration
@PropertySource("database.properties")
@ComponentScan("com.alter.spring")//添加注解扫描包,并且指定扫描路径。
public class AppScanConfig {

    @Value("${jdbc.driverClass}")
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Bean(destroyMethod = "close")
    public DruidDataSource druidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driverClassName);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }

    @Bean
    public QueryRunner queryRunner(DataSource dataSource){
        return new QueryRunner(dataSource);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值