Java框架-Spring概念及纯xml配置

1. 三层架构中的spring及spring概述

1.1 三层架构中的spring

Java框架-Spring概念及纯xml配置_第1张图片

  • Spring框架对三层架构都有支持,dao提供支持(如JDBCTemplate)、service提供事务支持、web提供了springmvc框架支持等。

1.2 Spring的概述

  • Spring是于2003年兴起的一个轻量级的Java开发开源框架。
  • 由Rod Johnson首次提出。
  • Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架

1.3 Spring优势

  • 方便解耦,简化开发
  • AOP编程的支持
  • 声明式事务的支持
  • 方便程序的测试
  • 方便继承各种优秀的框架
  • 降低JavaEE API的使用难度等

1.4 Spring体系结构

七大模块

  1. Spring Core:核心容器,Spring的基本功能
  2. Spring AOP:面向切面编程
  3. Spring ORM:提供多个第三方持久层框架的整合
  4. Spring DAO:简化DAO开发
  5. Spring Context:配置文件,为Spring提供上下文信息,提供了框架式的对象访问方法
  6. Spring Web:提供针对Web开发的集成特性
  7. Spring MVC:提供了Web应用的MVC实现

2. 程序中的耦合与解耦

  • 耦合:程序中的依赖关系。其中一种依赖关系是对象之间的关联性。对象之间关联性越高,维护成本越高。

  • 划分模块的一个准则就是高内聚低耦合

  • 高内聚,低耦合:类内部的关系越紧密越好,类与类之间的关系越少越好。

2.1 解决数据库驱动注册代码与连接数据库代码的耦合问题

  1. 使用反射注册驱动,用于解决两者依赖关系;
  2. 将驱动全限定类字符串写入配置文件中,注册驱动时加载配置文件,用于使用反射创建对象时驱动类字符串在代码中写死的问题

2.2 解决三层架构之间的耦合问题

表现层需要创建业务层的实例来调用业务层的方法,同样业务层也要创建持久层的示例来调用持久层的方法。按照传统开发方法,创建实例都是直接new,一旦更换数据库或者拓展已有业务(新的业务层接口实例),就会影响到原有的代码,需要修改源代码(也就是耦合问题)

解决耦合问题的关键,业务层或持久层的实例不手动直接创建,而是交由第三方(工厂)创建。通过修改工厂的配置文件获取对应的实例,不需要修改原有代码,实现解耦

下面简单举例

2.2.1 举例准备工作

  1. dao接口

    public interface IAccountDao {
        void save();
    }
    
  2. dao实现类

   //mysql
   public class AccountDaoImpl implements IAccountDao {
       @Override
       public void save() {
           System.out.println("mysql保存用户");
       }
   }

//oracle

public class AccountDaoOracleImpl implements IAccountDao {
    @Override
    public void save() {
        System.out.println("oracle保存用户");
    }
}
  1. service接口

    public interface IAccountService {
        void save();
    }
    
  2. service实现类

    public class AccountServiceImpl implements IAccountService {
        private IAccountDao accountDao = new AccountDaoImpl();
        @Override
        public void save() {
            accountDao.save();
        }
    }
    

2.2.2 使用工厂解耦

2.2.2.1 配置文件
#dao层
#mysql
AccountDao=com.azure.dao.impl.AccountDaoImpl
#oracle
#AccountDao=com.azure.dao.impl.AccountDaoOracleImpl

#service层
AccountService=com.azure.service.impl.AccountServiceImpl
2.2.2.2 工厂类
public class BeanFactory {
    /*
    读取properties配置文件有两种方式:
    1、直接创建properties对象,使用关联配置文件的输入流加载文件数据到properties中;
    2、通过ResourceBundle加载配置文件
        1)只可以加载properties后缀的配置文件
        2)只能加载类路径下的properties配置文件
     */
    //读取配置文件并创建对应的对象
    //使用泛型,通过传入泛型类型返回对应类型的对象
    public static <T> T getBean(String name,Class<T> clazz) {
        try {
            //读取配置文件数据
            ResourceBundle bundle = ResourceBundle.getBundle("instance");
            //获取key对应的value。比如AccountDao=com.azure.dao.impl.AccountDaoImpl
            String value = bundle.getString(name);
            return (T) Class.forName(value).getConstructor().newInstance();//jdk1.9做法
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
2.2.2.3 service层解耦
public class AccountServiceImpl implements IAccountService {
    private IAccountDao accountDao = BeanFactory.getBean("AccountDao", IAccountDao.class);
    @Override
    public void save() {
        accountDao.save();
    }
}
2.2.2.4 表现层解耦
  • 这里就在测试类中模拟
public class app {
    public static void main(String[] args) {
        //使用工厂创建service对象
        IAccountService accountService = BeanFactory.getBean("AccountService", IAccountService.class);
        accountService.save();
    }
}
2.2.2.5 小结

通过修改配置文件即可完成dao或service的转换,不需要修改已有代码

3. IOC

使用工厂类实现三层架构的解耦,其核心思想就是

  1. 通过读取配置文件使用反射技术创建对象;
  2. 将创建的对象存储。使用时直接取出存储的对象。

其核心思想归纳起来就是IOC(Inversion Of Control 控制反转)

3.1 IOC概念

  • 把创建对象的权利交给框架
  • 包含依赖注入(Dependency Injection)和依赖查找(Dependency Lookup)

4. Spring IOC容器

  • 简而言之,IOC容器是用来创建对象,并给对象属性赋值

下面将创建一个简单的IOC案例

4.1 创建简单案例

4.1.1 创建项目、添加依赖


<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.0modelVersion>

    <groupId>com.azuregroupId>
    <artifactId>day51projects_spring_IOCartifactId>
    <version>1.0-SNAPSHOTversion>
    <dependencies>
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.0.2.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
        dependency>
    dependencies>    
project>

4.1.2 创建实体类

public class User implements Serializable {
    public User(){
        //使用无参实例化User对象时都会进入
        System.out.println("创建User对象");
    }
}

4.1.3 ioc容器配置文件

  • 使用快捷方式创建,会自动引入约束

Java框架-Spring概念及纯xml配置_第2张图片


<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.azure.entity.User">bean>
beans>

4.1.4 测试类

public class Test01 {
    @Test
    public void test(){
        //创建ioc容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //从容器中获取对象
        User user = (User) ac.getBean("user");
        System.out.println(user);
    }
}

4.2 创建IOC容器的几种方式

1.FileSystemXmlApplicationContext:加载本地的配置文件

2.ClassPathXmlApplicationContext:加载类路径下的配置文件(重点)

3.AnnotationConfigWebApplicationContext:注解方式开发创建容器

4.WebApplicationContext:web项目中创建容器

5.BeanFactory:使用工厂创建对象

疑问:BeanFactory与ApplicationContext创建容器区别?

  • BeanFactory 在创建容器时候,没有自动创建对象

  • ApplicationContext 在创建容器时候,默认自动创建对象。

public class Test02 {

    /*1.FileSystemXmlApplicationContext:加载本地的配置文件*/
    @Test
    public void test_file(){
        //获得配置文件的真实路径
        String path = "E:\\Java_study\\JavaprojectsIV\\day51projects_spring_IOC\\src\\main\\resources\\bean.xml";
        //从容器中获取对象
        ApplicationContext ac = new FileSystemXmlApplicationContext(path);
        User user = (User) ac.getBean("user");
        System.out.println(user);
    }

    /*2.ClassPathXmlApplicationContext:加载类路径下的配置文件(重点)*/
    @Test
    public void test_class(){
        //类路径下要有bean.xml
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //从容器中获取对象
        User user = (User) ac.getBean("user");
        System.out.println(user);
    }

    /*3.AnnotationConfigWebApplicationContext:注解方式开发创建容器*/
    @Test
    public void test_annotation(){
        /*//程序中要有SpringConfig类,表示容器类(相当于bean.xml)
        ApplicationContext ac = new AnnotationConfigApplicationContext("SpringConfig.class");
        //从容器中获取对象
        User user = (User) ac.getBean("user");
        System.out.println(user);*/
    }
    /*4.使用BeanFactory顶级接口创建容器*/
    @Test
    public void test_factory(){
        Resource resource = new ClassPathResource("bean.xml");
        BeanFactory factory = new XmlBeanFactory(resource);
        User user = (User) factory.getBean("user");//创建User对象
    }
}

4.3 创建容器(bean标签)的具体配置

  • 常用配置

    id、class,可选scope、lazy-init、init-method、destroy-method


    <bean
            id="user"
            name="user2,user3"
            class="com.azure.entity.User"
            scope="prototype"
            lazy-init="true"
            init-method="init" destroy-method="preDestory">bean>
  • 注意事项:

    id和name的作用相同,均是指定对象的名称,用于通过该名称获取ioc容器中的对象。但是形式不同。id不能指定多个名称,name可以指定多个名称。按照实际开发,更常用的是id

4.4 创建对象的方式(控制反转)

4.4.1 调用无参构造函数创建对象

  • 使用无参数构造函数创建对象(有参数构造函数在依赖注入中讲述)
  1. 创建实体类

    在这里插入图片描述

  2. 在bean.xml中配置对应的bean标签
    Java框架-Spring概念及纯xml配置_第3张图片

4.4.2 使用工厂类的实例方法

  1. 创建工厂类

    public class UserFactory {
        /*1.通过实例方法返回对象*/
        public User createUser(){
            System.out.println("工厂实例方法创建一个对象");
            return new User();
        }
    }
    
  2. 配置bean.xml

    • 运用到的bean标签属性:
      • factory-bean:用于指定引用容器中的工厂对象;
      • factory-method:用于指定工厂对象的实例方法。
    
    
    <bean id="factory" class="com.azure.factory.UserFactory">bean>
    
    
    
    <bean id="user" factory-bean="factory" factory-method="createUser">bean>
    

4.4.3 使用工厂类的静态方法

  1. 工厂类中添加静态方法

    *2.通过静态方法返回对象*/
    public static User createUser_static(){
        System.out.println("工厂静态方法创建一个对象");
        return new User();
    }
    
  2. 配置bean.xml

    
    
    <bean id="user1" class="com.azure.factory.UserFactory" factory-method="createUser_static"/>
    

4.5 给对象属性赋值(DI依赖注入)

4.5.1调用有参构造函数创建对象

  1. 创建实体类对象

    public class Student {
        private int id;
        private String name;
        //使用有参构造函数创建对象,实体类必须有有参构造函数
        public Student(int id, String name) {
            this.id = id;
            this.name = name;
        }
        /*省略toString、getter&setter*/
    }
    
  2. 配置bean.xml

  • 常用index、value和ref三个属性

    
    
    <bean id="student" class="com.azure.entity.Student">
        <constructor-arg index="0" value="10">constructor-arg>
        <constructor-arg index="1" ref="str">constructor-arg>
    bean>
    
    <bean id="str" class="java.lang.String">
        <constructor-arg index="0" value="明明">constructor-arg>
    bean>
    

4.5.2 使用set方法注入依赖

  1. 创建实体类对象,并提供set方法给对象属性赋值

    • 注意:实体类对象必须有无参构造函数
  2. 配置bean.xml

    
    
    <bean id="student2" class="com.azure.entity.Student">
        <property name="id" value="12">property>
        <property name="name" ref="str">property>
    bean>
    

4.5.3 使用p名称空间注入依赖

  • 也是调用set方法给对象属性赋值

  • 在spring3.0之后版本才有的,主要目的是为了简化配置

  • 配置bean.xml,配置时要在beans标签中引入xmlns:p="http://www.springframework.org/schema/p"


    
    <bean id="student3" class="com.azure.entity.Student" p:id="168" p:name-ref="str">bean>

4.6 给集合属性赋值

  1. 实体类,要有set/get方法

    Java框架-Spring概念及纯xml配置_第4张图片

  2. 配置bean.xml

    
    <bean id="students" class="com.azure.entity.Student">
        
        <property name="list">
            <list>
                <value>cnvalue>
                <value>usavalue>
            list>
        property>
    
        
        <property name="set">
            <set>
                <value>cnvalue>
                <value>usavalue>
            set>
        property>
    
        
        <property name="map">
            <map>
                <entry key="cn" value="China"/>
                <entry key="usa" value="America"/>
            map>
        property>
    
        
        <property name="properties">
            <props>
                <prop key="cn">Chinaprop>
                <prop key="usa">Americaprop>
            props>
        property>
    bean>
    

5. 使用纯xml改造三层架构案例

  1. 添加依赖(pom.xml)

    <dependencies>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.30version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.0.2.RELEASEversion>
        dependency>
    dependencies>
    
  2. service的实例

    public class AccountServiceImpl implements IAccountService {
    
        /*由spring的ioc容器注入dao*/
        private IAccountDao accountDao;//先定义dao对象
        //注入方法(对应bean.xml中的property标签)
        //使用set方法给dao对象赋值!!方法的参数就是ioc容器中保存的dao对象
        public void setAccountDao(IAccountDao accountDao) {
            this.accountDao=accountDao;
        }
    
        @Override
        public void save() {
            accountDao.save();
        }
    }
    
  3. 配置bean.xml

    
    <bean id="accountDao" class="com.azure.dao.impl.AccountDaoImpl">bean>
    
    <bean id="accountService" class="com.azure.service.impl.AccountServiceImpl">
        
        <property name="accountDao" ref="accountDao">property>
    bean>
    
  4. 测试类

    public class app {
        public static void main(String[] args) {
            //创建容器
            ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
            //使用工厂创建service对象
            IAccountService accountService = ac.getBean("accountService", IAccountService.class);
            accountService.save();
        }
    }
    

5.1 小结

  • 该改造方法的思路是

    1. 在ioc容器中创建dao对象,对应bean.xml中的第一个bean标签;
    2. 在ioc容器中创建service对象,而service对象中包含dao对象(需要使用dao对象调用dao层方法),所以需要将ioc的dao对象赋值给service里面的dao对象。本例中是使用set方法将ioc的dao对象注入,所以使用到property标签;
    3. 因为使用set方法注入dao,所以在service类中需要提供dao对象的set方法
  • 所谓的注入依赖,就是给对象属性赋值

6. 使用spring的IOC实现CRUD(基于xml)

  • 需求:根据三层架构,使用基于xml的spring实现CRUD

6.1 准备工作

  • 准备account表,并使主键自增。表格包括字段accountId(主键)、uid、money

6.2 环境搭建

6.2.1pom.xml配置


<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.0modelVersion>

    <groupId>com.azuregroupId>
    <artifactId>day52projects_spring_xmlartifactId>
    <version>1.0-SNAPSHOTversion>
<dependencies>
    
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-contextartifactId>
        <version>5.0.2.RELEASEversion>
    dependency>
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-jdbcartifactId>
        <version>5.0.2.RELEASEversion>
    dependency>
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-txartifactId>
        <version>5.0.2.RELEASEversion>
    dependency>
    
    <dependency>
        <groupId>com.alibabagroupId>
        <artifactId>druidartifactId>
        <version>1.1.10version>
    dependency>
    
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>5.1.32version>
    dependency>
    
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.12version>
    dependency>
dependencies>  
project>

6.3 实体类

public class account {
    private int accountId;
    private int uid;
    private double money;
    /*省略无参、有参、toString、getter&setter*/
}

6.4 dao代码

6.4.1 dao接口代码

public interface IAccountDao {
    //添加
    void save(Account account);
    //更新
    void update(Account account);
    //删除
    void delete(int aid);
    //查询
    List<Account> findAll();
}

6.4.2 dao实现类

public class AccountDaoImpl implements IAccountDao {

    private JdbcTemplate jdbcTemplate;
    /*使用SpringIOC容器注入jdbcTemplate对象,提供set方法*/
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public void save(Account account) {
        jdbcTemplate.update("insert into account values (null,?,?)",account.getUid(),account.getMoney());
    }

    @Override
    public void update(Account account) {
        jdbcTemplate.update("update account set  uid=?,money=? where accountId=?",account.getUid(),account.getMoney(),account.getAccountId());
    }

    @Override
    public void delete(int id) {
        jdbcTemplate.update("delete from account where accountId=?",id);
    }

    @Override
    public List<Account> findAll() {
        return jdbcTemplate.query("select * from account",new BeanPropertyRowMapper<>(Account.class));
    }
}

6.5 service层

6.5.1 service接口

public interface IAccountService {
    //添加
    void save(Account account);
    //更新
    void update(Account account);
    //删除
    void delete(int id);
    //查询
    List<Account> findAll();
}

6.5.2 service实现类

public class AccountServiceImpl implements IAccountService {
    
    private IAccountDao accountDao;
    /*使用SpringIOC容器注入dao对象,提供set方法*/
    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void save(Account account) {
        accountDao.save(account);
    }
    @Override
    public void update(Account account) {
        accountDao.update(account);
    }
    @Override
    public void delete(int id) {
        accountDao.delete(id);
    
    @Override
    public List<Account> findAll() {
        return accountDao.findAll();
    }
}

6.6 spring配置(重点)


<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="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver">property>
        <property name="url" value="jdbc:mysql:///mybatis?characterEncoding=utf8">property>
        <property name="username" value="root">property>
        <property name="password" value="root">property>
    bean>
    
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource">property>
    bean>
    
    <bean id="accountDao" class="com.azure.dao.impl.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate">property>
    bean>
    
    <bean id="accountService" class="com.azure.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao">property>
    bean>
beans>

6.7 测试类

public class WebApp {
    /*测试类中创建容器获取service对象*/
    private ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    private IAccountService accountService = (IAccountService) ac.getBean("accountService");


    @Test
    public void save() {
        Account account = new Account();
        account.setUid(46);
        account.setMoney(99D);

        accountService.save(account);
    }
    @Test
    public void update() {
        Account account = new Account();
        account.setAccountId(1);
        account.setUid(46);
        account.setMoney(99D);

        accountService.update(account);
    }
    @Test
    public void delete() {
        accountService.delete(4);
    }
    @Test
    public void findAll() {
        System.out.println(accountService.findAll());
    }
}

6.8 bean配置文件优化

将数据库连接设置放在jdbc.properties中,bean.xml里面加载文件。

  • 方便修改数据库连接,同时保证账户信息安全
  1. 使用标签标签加载properties文件;注意写法
  2. 在连接池配置中使用${}获取配置文件中指定key的value值

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    
    
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        
        <property name="driverClassName" value="${jdbc.driver}}">property>
        <property name="url" value="${jdbc.url}">property>
        <property name="username" value="${jdbc.username}">property>
        <property name="password" value="${jdbc.password}">property>
    bean>
    
    
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource">property>
    bean>
    
    <bean id="accountDao" class="com.azure.dao.impl.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate">property>
    bean>
    
    <bean id="accountService" class="com.azure.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao">property>
    bean>
beans>

你可能感兴趣的:(spring)