zoukankan      html  css  js  c++  java
  • Spring IOC 概念及作用

    一:程序之间的耦合及解决

      耦合性(Coupling):也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。耦合性存在于各个领域,而非软件设计中独有的。
      在软件工程中,耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合。

    1:耦合的分类

    ①:内容耦合:
      当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用之。
    ②:公共耦合:
      两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在具有大量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。
    ③: 外部耦合 :
      一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。
    ④: 控制耦合 :
      一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进行适当的动作,这种耦合被称为控制耦合。
    ⑤:标记耦合 :
      若一个模块 A 通过接口向两个模块 B 和 C 传递一个公共参数,那么称模块 B 和 C 之间存在一个标记耦合。
    ⑥: 数据耦合:
      模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某些模块的输出数据作为另一些模块的输入数据。
    ⑦: 非直接耦合 :
      两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的。

    2:耦合总结

      耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。

    3:扩展(内聚和耦合的使用)

      内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。 程序讲究的是低耦合,高内聚。就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却要不那么紧密。内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合。

    4:呈现耦合的代码片段

    ##### 第一种常见的耦合状态
    /**
     * 学生业务处理实现类
     * @author ant
     */
    public class StudentServiceImpl implements StudentService {
    
        //组合了持久层对象
        private StudentDao studentDao = new StudentDaoImpl();
    
        /**
         * @method 模拟保存学生方法实现
         */
        public void save() {
            //调用dao的保存数据方法
            studentDao.save();
        }
    }
    // 业务层调用持久层,并且此时业务层在依赖持久层的接口和实现类。
    // 如果此时没有持久层实现类,编译将不能通过。这种编译期依赖关系,
    // 应该在我们开发中杜绝。我们需要优化代码解决。
    
    
    ##### 第二种耦合
    // 问题:在JDBC注册驱动时我们为什么不使用 DriverManager 的 registerDriver 方法,而是采用 Class.forName("xxx") 的方式?
    
    //1.注册驱动
    //DriverManager.registerDriver(new com.mysql.jdbc.Driver()); 为什么不使用这个
            Class.forName("com.mysql.jdbc.Driver");
    //2.获取连接
    //3.获取预处理 sql 语句对象
    //4.获取结果集
    //5.遍历结果集
    
    // 回答:其实我们的类依赖了数据库的具体驱动类(MySQL),
    // 如果使用registerDriver方法注册,会存在一定的耦合,依赖具体的驱动类,如果不存在com.mysql.jdbc.Driver类,则运行都不行,
    // 而Class.forName则解决了这种问题,因为它是接收字符串,不在依赖具体驱动类,同时,也产生了一个新的问题,mysql 驱动的全限定类名字符串是在 java 类中写死的,一旦要改还是要修改源码。解决这个问题也很简单,使用配置文件配置。不使用工厂模式展示代码耦合
    程序耦合的2个小实例

    5:使用工厂模式解耦

      在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。那么,这个读取配置文件,创建和获取三层对象的类就是工厂

    工厂创建的对象存在哪呢?:

      那肯定要要找个集合来存。这时候有 Map 和 List 供选择。到底选 Map 还是 List 就看我们有没有查找需求。有查找需求,选 Map。所以我们的答案就是在应用加载时,创建一个 Map,用于存放三层对象。我们把这个 map 称之为容器。

    什么是工厂呢?:

      工厂就是负责给我们从容器中获取指定对象的类。这时候我们获取对象的方式发生了改变。

     ①:不使用工厂模式之前的耦合代码

    #####StudentDao接口
    
    public interface StudentDao {
        /**
         * @method 模拟保存学生接口方法
         */
        void save();
    }
    
    +++++++++++++++++++++++++++++++++++++++++
            #####StudentDao接口实现类
    
    public class StudentDaoImpl implements StudentDao {
        /**
         * @method 模拟保存学生方法实现
         */
        public void save() {
            System.out.println("==》保存完成《==");
        }
    }
    
    +++++++++++++++++++++++++++++++++++++++++
            ##### StudentService业务接口
    
    public interface StudentService {
        /**
         * @method 模拟保存学生接口方法
         */
        void save();
    }
    
    +++++++++++++++++++++++++++++++++++++++++
            ##### StudentServiceImpl 业务接口实现类
    
    /**
     * 学生业务处理实现类
     * @author ant
     */
    public class StudentServiceImpl implements StudentService {
        //组合
        private StudentDao studentDao = new StudentDaoImpl();
    
        /**
         * @method 模拟保存学生方法实现
         */
        public void save() {
            //调用dao的保存数据方法
            studentDao.save();
        }
    }
    
    +++++++++++++++++++++++++++++++++++++++++
            ##### 测试类
    
    public class Client {
        public static void main(String[] args) throws SQLException {
            //创建StudentService对象实体后调用操作
            StudentService studentService=new StudentServiceImpl();
            studentService.save();
        }
    }
    
    //这个就是我们平常写的三层架构,成功的展示了代码的耦合,这时候随便删除一个类代码都会报代码错误
    不使用工厂模式展示代码耦合

     ②:使用工厂模式进行解耦

    ##### 第一种工厂对象  产生的是多例对象 
    /**
     * 第一种它是多例,这个工厂效率低,因为每次调用都要重新匹配,
     * 然后获取和实例化返回,来回创建对象,会对程序的性能有所影响
     */
    public class BeanFactory {
        //聚合Properties配置类
        private static Properties prop;
        //初始化Properties数据
        static {
            prop = new Properties();
            try {
                //获取文件加载到Properties对象里
                prop.load(BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"));
            } catch (Exception e) {
                throw new RuntimeException("读取配置失败");
            }
        }
        //根据键获取相应对象
        public static Object getBean(String name) {
            //根据键获取value
            String property = prop.getProperty(name);
            Object obj = null;
            try {
                //通过反射获取对象实例 每次都重新实例化
                obj = Class.forName(property).getConstructor().newInstance();
            } catch (Exception e) {
                throw new RuntimeException("无法注册");
            }
            //返回对象
            return obj;
        }
    }
    
    +++++++++++++++++++++++++++++++++++++++++
    ##### 第二种工厂对象  产生的是单例对象 
    /**
     * 这种是简单的单例工厂,把数据全部存放于容器中,然后要的时候获取,
     */
    public class BeanFactory {
        //聚合Properties配置类
        private final static Properties prop;
        //创建容器存储对象
        private final static Map<String, Object> beans;
    
        //初始化
        static {
            //为2个对象赋值
            prop = new Properties();
            beans = new HashMap<String, Object>();
            try {
                //获取文件加载到Properties对象里
                prop.load(BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"));
                //获取配置文件全部key
                Enumeration<Object> keys = prop.keys();
                //循环获取值 然后实例化存储到map容器
                while (keys.hasMoreElements()) {
                    String key = keys.nextElement().toString();
                    String value = prop.getProperty(key);
                    Object bean = Class.forName(value).getConstructor().newInstance();
                    beans.put(key, bean);
    
                }
            } catch (Exception e) {
                throw new RuntimeException("读取配置失败");
            }
        }
    
        //根据键获取相应对象
        public static Object getBean(String name) {
            //从容器获取返回
            if (beans.containsKey(name)) {
                return beans.get(name);
            }
            return null;
        }
    }
    工厂的2种写的方式
    ##### StudentDao持久层接口
    public interface StudentDao {
        /**
         * @method 模拟保存学生接口方法
         */
        void save();
    }
    
    +++++++++++++++++++++++++++++++++++++++++
    ##### StudentDaoImpl持久层接口实现类
    public class StudentDaoImpl implements StudentDao {
        /**
         * @method 模拟保存学生方法实现
         */
        public void save() {
            System.out.println("==》保存完成《==");
        }
    }
    
    +++++++++++++++++++++++++++++++++++++++++
    ##### StudentService业务层接口
    public interface StudentService {
        /**
         * @method 模拟保存学生接口方法
         */
        void save();
    }
    
    +++++++++++++++++++++++++++++++++++++++++
    ##### StudentServiceImpl业务接口实现类
    public class StudentServiceImpl implements StudentService {
        //聚合StudentDao接口
        private static StudentDao studentDao;
        //初始化
        static{
            studentDao = (StudentDaoImpl)BeanFactory.getBean("studentDao");
        }
        /**
         * @method 模拟保存学生方法实现
         */
        public void save() {
            //调用dao的保存数据方法
            studentDao.save();
        }
    }
    
    +++++++++++++++++++++++++++++++++++++++++
    ##### 测试类
    public class Client {
        public static void main(String[] args) throws SQLException {
            //创建StudentService对象实体后调用操作
            StudentService studentService=(StudentServiceImpl) BeanFactory.getBean("studentService");
            studentService.save();
        }
    }
    基本代码及测试
    studentDao=cn.xw.dao.impl.StudentDaoImpl
    studentService=cn.xw.service.impl.StudentServiceImpl
    bean.properties配置文件

    小总结:其实我们在日常开发中,都是不用手动写控制反转(解耦)都是由Spring帮我们完成了,因为Spring核心就包括IOC

    二:Spring IOC解决程序耦合

    1:相应资料

      Spring官网     

      注意:我们现在开发用的Spring版本都是5版本以上的,用jdk8编写的,同时tomcat版本也要在8.5以上

    <!--编写Spring必须要导入相应坐标-->
    <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.6.RELEASE</version>
            </dependency>
        </dependencies>

    2:使用Spring实现IOC解决耦合

     ①:编写Service和Dao接口及实现类

    ##### StudentDao持久层接口
    public interface StudentDao {
        /**
         * @method 模拟保存学生接口方法
         */
        void save();
    }
    
    +++++++++++++++++++++++++++++++++++++++++
    ##### StudentDaoImpl持久层接口实现类
    public class StudentDaoImpl implements StudentDao {
        /**
         * @method 模拟保存学生方法实现
         */
        public void save() {
            System.out.println("==》保存完成《==");
        }
    }
    
    +++++++++++++++++++++++++++++++++++++++++
    ##### StudentService业务层接口
    public interface StudentService {
        /**
         * @method 模拟保存学生接口方法
         */
        void save();
    }
    
    +++++++++++++++++++++++++++++++++++++++++
    ##### StudentServiceImpl业务接口实现类
    public class StudentServiceImpl implements StudentService {
        //聚合StudentDao接口
        private static StudentDao studentDao;
        /**
         * @method 模拟保存学生方法实现
         */
        public void save() {
            ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
            studentDao = app.getBean("studentDao", StudentDao.class);
    
            //调用dao的保存数据方法
            StudentServiceImpl.studentDao.save();
        }
    }
    Dao和Service

    ②:编写Spring配置文件

    <?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
            https://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--把StudentServiceImpl创建放入IOC容器-->
        <bean id="studentService" class="cn.xw.service.impl.StudentServiceImpl"></bean>
        <!--把StudentDaoImpl创建放入IOC容器-->
        <bean id="studentDao" class="cn.xw.dao.impl.StudentDaoImpl"></bean>
    </beans>
    编写applicationContext.xml

     ③:测试类

    public class Client {
        public static void main(String[] args) throws SQLException {
            ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
            StudentService studentService = app.getBean("studentService", StudentService.class);
            studentService.save();
        }
    }
    测试类代码

    进行测试后发现是可以运行的,但是问题来啦,这写的是啥玩意,也看不懂呀,这可咋整,所以这前面代码只是Spring的简单入门,在接下来我就会为大家详细介绍Spring IOC

    3:导包的不同方式

     1 手动导入Spring的jar包
     2     spring-aop-5.0.2.RELEASE.jar
     3     spring-beans-5.0.2.RELEASE.jar
     4     spring-context-5.0.2.RELEASE.jar
     5     spring-core-5.0.2.RELEASE.jar
     6     spring-expression-5.0.2.RELEASE.jar
     7     commons-logging-1.2.jar
     8 
     9 
    10 
    11 在Maven下 我们只需要导入坐标即可
    12     <dependency>
    13         <groupId>org.springframework</groupId>
    14         <artifactId>spring-context</artifactId>
    15         <version>5.2.6.RELEASE</version>
    16     </dependency>
    17 但是我们看看maven给我们导入的jar包
    18 Maven: org.springframework:spring-aop:5.2.6.RELEASE
    19 Maven: org.springframework:spring-beans:5.2.6.RELEASE
    20 Maven: org.springframework:spring-context:5.2.6.RELEASE
    21 Maven: org.springframework:spring-core:5.2.6.RELEASE
    22 Maven: org.springframework:spring-expression:5.2.6.RELEASE
    23 Maven: org.springframework:spring-jcl:5.2.6.RELEASE
    24 
    25 问题来啦,大家会看见我们手动导入的logging和maven导入的jcl其实是一样的
    26 因为maven把logging日志jar包封装到了jcl中
    导包方式

    三:Spring之IOC详细介绍(基于XML)

     1:Spring中IOC实现的工厂类图结构

     2:BeanFactory和ApplicationContext的区别

     在上面一个入门的例子中,大家看我都是使用ApplicationContext及它的实现类来加载配置文件和创建容器的,可是它们的区别是什么?我们仔细看BeanFactory是最顶层的接口,而ApplicationContext是它的子接口,唯一的区别是:

    ApplicationContext:它在构造核心容器时,创建对象采取的策略是采用立即加载的方式,也就是说,只要一读取完配置文件后就会马上创建配置文件中的对象,然后放入容器中。就像我之前写的第二种工厂方式,把读取的配置文件获取的对象放入Map中。

    BeanFactory:它在创建核心容器时,创建对象采取的策略是延迟加载的的方式,也就是说,什么是根据id获取对象的时候才去创建,然后放入容器中

    3:ApplicationContext接口的实现类

    ①:ClassPathXmlApplicationContext

      它可以加载类路径下的任何资源,不在就无法加载,src下的都是类路径,如果在src下是多文件(如在src下的file里面的applicationContext.xml),路径就要写file/applicationContext.xml

    ②:FileSystemXmlApplicationContext

      加载磁盘下任意文件,必须要有访问权限

    ③:AnnotationConfigApplicationContext

      用于读取注解,在注解开发会详细说

    //加载类路径下的资源
    ApplicationContext appA=new ClassPathXmlApplicationContext("applicationContext.xml");
    //加载任意文件下的资源
    ApplicationContext appB=new FileSystemXmlApplicationContext("D:\bky_Spring001\src\main\resources\applicationContext.xml");

    4:获取容器对象

    //2种获取容器对象的方法
    //第一种:参数1 容器id属性    参数2 映射的class对象
    StudentService studentServiceA = app.getBean("studentService", StudentService.class);
    //第二种: 参数1 容器id属性
    StudentService studentServiceB = (StudentServiceImpl)app.getBean("studentService");

    5:Spring配置文件bean的三种创建方式

    <!--以下面的这个对象为例    下面的3种只能有一种存在-->
        <!--第一种 使用默认构造函数创建,前提必须要有无参构造函数,如果没有无参构造函数无法创建-->
        <bean id="studentDao" class="cn.xw.dao.impl.StudentDaoImpl"></bean>
        
        <!--第二种创建方式 使用工厂方法创建对象-->
        <!--factory-bean:引用工厂对象路径 -->
        <!--factory-method:调用工厂中的方法 返回一个对象容器-->
        <bean id="beanFactory" class="cn.xw.utils.BeanFactory"></bean>
        <bean id="studentDao" factory-bean="beanFactory" factory-method="getStudentService"></bean>
    
        <!--第三种 使用工厂的静态方法创建对象放到容器中  前提方法必须是静态的-->
        <bean id="studentDao" class="cn.xw.utils.BeanFactory" factory-method="getstaticStudentService"></bean>
    //工厂对象
    public class BeanFactory {
        //普通方法
        public StudentDao getStudentService(){
            return new StudentDaoImpl();
        }
        //静态方法
        public static StudentDao getstaticStudentService(){
            return new StudentDaoImpl();
        }
    }

    6:Spring中bean的作用范围(单例或多例)

    其实Spring是一个很好的框架,在使用工厂IOC的时候可以指定是单例还是多例

     bean标签参数:scope=“xx” 作用范围

    ①:singleton:     单例对象  默认
    ②:prototype:  多例对象
    ③:request:    作用域web的请求范围
    ③:session: 作用域web的会话范围
    ④:global-session: 作用域web集群会话
    <!--把StudentDaoImpl创建放入到IOC容器  并设置了单例对象 默认就是单例-->
        <bean id="studentDao" class="cn.xw.dao.impl.StudentDaoImpl" scope="singleton"></bean>

    7:Spring中bean生命周期

    singleton:单例对象生命周期      prototype:多例对象生命周期
    出生:容器创建时对象创建          出生:使用Spring创建,获取时再创建
    活着:容器存在,对象一直存在        活着:对象在使用中一直存在
    死亡:IOC容器对象销毁,对象也就消亡     死亡:长时间不用会被JVM垃圾回收器回收
    总结:和IOC容器的生命周期一样           总结:和我们平时创建对象一样,长时间不用被回收

     ①:单例模式代码演示

    <!-更改配置文件-->
    <!--把StudentServiceImpl创建放入IOC容器-->
    <bean id="studentService" class="cn.xw.service.impl.StudentServiceImpl"
          scope="singleton" init-method="init" destroy-method="destroy"></bean>
    public class StudentServiceImpl implements StudentService {
        //聚合StudentDao接口
        private static StudentDao studentDao=new StudentDaoImpl();
        /**
         * @method 模拟保存学生方法实现
         */
        public void save() {
            //调用dao的保存数据方法
            StudentServiceImpl.studentDao.save();
        }
        //加载方法
        public void init(){
            System.out.println("对象被   加载了");
        }
        //销毁方法
        public void destroy(){
            System.out.println("对象被   销毁了");
        }
    }
     //因为ApplicationContext没有关闭方法,而子类重写了父类方法,还增加了关闭方法,所以改用子类
            ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
            //获取对象  这个是会初始化类 执行init方法
            StudentService studentServiceA = app.getBean("studentService", StudentService.class);
            //调用主体方法
            studentServiceA.save();
            //关闭
            app.close();

    注:单例模式下对象是可以进行关闭的,但是ApplicationContext没有关闭方法,所以要去子类寻找 ,还有 注意一下,Spring5.0.2是可以打印日志的,但是Spring再高版本需要手动设置才可以打印

    ②:多例模式代码演示

    <!--把StudentServiceImpl创建放入IOC容器-->
        <bean id="studentService" class="cn.xw.service.impl.StudentServiceImpl"
              scope="prototype" init-method="init" destroy-method="destroy"></bean>

     其它代码和上面一样,那么为什么关闭方法没有执行?,因为创建的对象为普通对象,Spring不知道你什么时候关闭,所以对象交给JVM垃圾回收器管理

     8:Spring依赖注入(重要)

     大家在前面有没有发现,我们把对象交给Spring管理的时候,我们之前用的是无参构造方法,可是有个疑问,我要创建带参构造函数怎么办?

    public class StudentServiceImpl implements StudentService {
        //聚合StudentDao接口
        private static StudentDao studentDao;
        /**
         * @method 模拟保存学生方法实现
         */
        public void save() {
            ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
            studentDao = app.getBean("studentDao", StudentDao.class);
            //调用dao的保存数据方法
            StudentServiceImpl.studentDao.save();
        }
    }

    这上面标红的在这里面使用重新加载读取配置文件,重新返回容器里某个对象,是否合适呢?其实是很不合适的,但是Spring已经为我们想到了这些问题,使用依赖注入的方法

    依赖注入(Dependency Injection):

      它是Spring框架核心IOC的具体表现,在编程的时候我们通过控制反转交给Spring容器管理对象,但是不能完全实现依赖解耦,这个时候就需要使用到依赖注入了(就是在当前类使用到其他类,这个时候由Spring为当前类提供其它类对象)

    IOC作用:降低程序耦合
    依赖关系管理:交给Spring完成
    依赖注入数据有三种:
      基本类型
      其他bean类型(在bean.xml注解的)
      复杂类型/集合类型

     ①:构造函数注入

    public class Student {
        private String name;
        private int age;
        private Date birthday;
        private Dog dog;
        //省略有参构造函数/get/set/toString
    }
    
    public class Dog {
        private String name;
        private String color;
        //省略有参构造函数/get/set/toString
    }
    实体类对象
     <!--配置Student对象-->
        <bean id="student" class="cn.xw.domain.Student">
            <constructor-arg name="name" value="张三"></constructor-arg>
            <constructor-arg name="age" value="25"></constructor-arg>
            <!--因为birthday是日期类型,所以我要引用下面的一个日期类型-->
            <constructor-arg name="birthday" ref="date"></constructor-arg>
            <!--因为dog是自定义对象Dog类型,所以我引用下面的Dog对象-->
            <constructor-arg name="dog" ref="dog"></constructor-arg>
        </bean>
        <!--配置Date对象-->
        <bean id="date" class="java.util.Date">
            <constructor-arg name="date" value="12345644556"></constructor-arg>
        </bean>
        <!--配置Dog对象-->
        <bean id="dog" class="cn.xw.domain.Dog">
            <constructor-arg name="name" value="大黄"></constructor-arg>
            <constructor-arg name="color" value="黄色"></constructor-arg>
        </bean>
        <!--
            constructor-arg:用来声明构造函数里面的参数的
            ++++++++++++用来指定给那个参数赋值++++++++++++
            index:使用索引的方式来和构造函数列表匹配 下标0开始
            type:用来注入指定数据类型来匹配
            name:用来匹配构造函数里参数的名称来赋值  最常用
            ++++++++++++设定值++++++++++++
            value:直接设置值即可
            rel:用来设置那些对象属性,引用其它对象
        -->
    applicationContext.xml配置文件
    public class Client {
        public static void main(String[] args) throws SQLException, InterruptedException {
            //创建ApplicationContext对象
            ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
            //获取对象
            Student student = app.getBean("student", Student.class);
            //打印对象
            System.out.println(student.toString());
            //打印结果:Student{name='张三', age=25, birthday=Sun May 24 05:20:44 CST 1970, dog=Dog{name='大黄', color='黄色'}}
        }
    }
    测试方法

    ②:set依赖注入

    因为set注入必须要有属性的全部set方法,而且还得提供一个无参的构造函数,所以对上面的实体类添加一个无参构造函数,接下来我对配置文件改造成set注入

    <!--配置Student对象-->
        <bean id="student" class="cn.xw.domain.Student">
            <property name="name" value="张三"></property>
            <property name="age" value="25"></property>
            <!--因为birthday是日期类型,所以我要引用下面的一个日期类型-->
            <property name="birthday" ref="date"></property>
            <!--因为dog是自定义对象Dog类型,所以我引用下面的Dog对象-->
            <property name="dog" ref="dog"></property>
        </bean>
        <!--配置Date对象-->
        <bean id="date" class="java.util.Date">
            <property name="time" value="12345644556"></property>
        </bean>
        <!--配置Dog对象-->
        <bean id="dog" class="cn.xw.domain.Dog">
           <property name="name" value="大黄"></property>
            <property name="color" value="黄色"></property>
        </bean>
        <!--
           property:用于set注入
           注意:set注入是找到set方法后去除set字母把后面的字母全部换成小写
           如:setName(String name)==>setName==>Name==>name==>最终找到name
        -->
    set注入

    ③:复杂类型注入

     我们前面学习了普通的类型注入,但是如果遇到数组、集合、键值对怎么注入呢?接下来我就带大家来讨论一下!

    public class Student {
        private String [] arrays;       //数组类型
        private List<String> list;      //有序集合
        private Set<String> sets;       //无序集合
        private Map<String,String> maps;//Map集合
        private Properties properties;  //properties键值对
        public void setArrays(String[] arrays) {
            this.arrays = arrays;
        }
        public void setList(List<String> list) {
            this.list = list;
        }
        public void setSets(Set<String> sets) {
            this.sets = sets;
        }
        public void setMaps(Map<String, String> maps) {
            this.maps = maps;
        }
        public void setProperties(Properties properties) {
            this.properties = properties;
        }
        @Override
        public String toString() {
            System.out.println(arrays);
            System.out.println(list);
            System.out.println(sets);
            System.out.println(maps);
            System.out.println(properties);
            return null;
        }
    }
    实体类
    <!--配置Student对象-->
        <bean id="student" class="cn.xw.domain.Student">
            <!--注入数组类型-->
           <property name="arrays">
              <array>
                  <value>arraysA</value>
                  <value>arraysB</value>
                  <value>arraysC</value>
              </array>
           </property>
            <!--注入集合类型-->
            <property name="list">
                <list>
                    <value>listA</value>
                    <value>listB</value>
                    <value>listC</value>
                </list>
            </property>
            <!--注入set类型-->
            <property name="sets">
                <set>
                    <value>setA</value>
                    <value>setB</value>
                    <value>setC</value>
                </set>
            </property>
            <!--注入键值对类型-->
            <property name="maps">
                <map>
                    <entry key="mapkeyA" value="mapValueA"></entry>
                    <entry key="mapkeyB" value="mapValueB"></entry>
                    <entry key="mapkeyC" value="mapValueC"></entry>
                </map>
            </property>
            <!--注入配置文件类型-->
            <property name="properties">
                <props>
                    <prop key="propskeyA" >propsValueA</prop>
                    <prop key="propskeyB" >propsValueB</prop>
                    <prop key="propskeyC" >propsValueC</prop>
                </props>
            </property>
        </bean>
    applicationContext.xml配置文件

    注:Arrays、List、Set是一组 Map、Properties是一组,上面2组同类的标签是可以相互替换的,因为类型都一样,正常单列数据使用List,键值对数据使用Map即可

     9:使用Spring基于XML完成对数据的CRUD操作(基于XML小总结)

    本案例实现对学生表的CRUD操作,为了更好的体现出上面讲的知识,我准备使用Spring基于XML开发,因为没有涉及到web页面,所以就建一个maven普通项目,不使用框架,其它技术有MySQL数据库、dbutils工具包、C3P0连接池

    资料导入:MySQL建表语句

    public class Student {
        private int sid;            //主键id
        private String sname;       //姓名
        private String ssex;        //性别
        private int sage;           //年龄
        private double scredit;     //学分
        private double smoney;      //零花钱
        private String saddress;    //住址
        private String senrol;      //入学时间
        //因为简单的单表CRUD就不涉及到外键
        //private int fid;            //外键 连接家庭表信息学生对家庭,一对一
        //private int tid;            //外键 连接老师信息 学生对老师,一对一
        //创建构造器/get/set/toString就不展示了
    }
    实体类
    <dependencies>
            <!--mysql驱动-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.32</version>
            </dependency>
            <!--工具类 操作数据库-->
            <dependency>
                <groupId>commons-dbutils</groupId>
                <artifactId>commons-dbutils</artifactId>
                <version>1.7</version>
            </dependency>
            <!--连接池-->
            <dependency>
                <groupId>c3p0</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.1.2</version>
            </dependency>
            <!--Spring坐标-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.6.RELEASE</version>
            </dependency>
            <!--单元测试-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
        </dependencies>
    pom.xml坐标
    #####接口
    /**
     * 学生数据操作Dao接口
     * @author ant
     */
    public interface StudentDao {
        //查询全部学生
        List<Student> findAll();
        //查询多个学生,根据姓名和地址模糊查询
        List<Student> findByLikeNameAndLikeAddress(String name, String address);
        //查询单个学生根据id
        Student findById(Integer id);
        //查询学生总数
        Integer totalCount();
        //添加学生
        Integer add(Student student);
        //更新学生
        Integer update(Student student);
        //删除学生
        Integer delete(Integer id);
    }
    +++++++++++++++++++++++++++++++++++++++++
    
    ######实现类
    /**
     * 学生数据操作Dao实现类
     * @author ant
     */
    public class StudentDaoImpl implements StudentDao {
        //聚合dbutils工具类
        private QueryRunner query;
        //有构造方法注入和set注入  这里选择set注入 不修改无参构造器
        public void setQuery(QueryRunner query) {
            this.query = query;
        }
    
        //查询全部学生
        public List<Student> findAll() {
            //初始化查询后封装的数据变量
            List<Student> students = null;
            //Sql语句
            String sql = "select * from student";
            //异常处理
            try {
                //执行sql语句并查询数据
                students = query.query(sql, new BeanListHandler<Student>(Student.class));
            } catch (SQLException e) {
                e.printStackTrace();
            }
            //返回数据
            return students;
        }
    
        //查询多个学生,根据姓名和地址模糊查询
        public List<Student> findByLikeNameAndLikeAddress(String name, String address) {
            List<Student> students = null;
            String sql = "select * from student where sname like ? and saddress like ? ";
            try {
                students = query.query(sql, new BeanListHandler<Student>(Student.class), name, address);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return students;
        }
    
        //查询单个学生根据id
        public Student findById(Integer id) {
            Student student = null;
            try {
                student = query.query("select * from student where sid=?", new BeanHandler<Student>(Student.class), id);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return student;
        }
    
        //查询学生总数
        public Integer totalCount() {
            Integer total = 0;
            try {
                total = query.query("select count(sid) from student", new ScalarHandler<Integer>());
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return total;
        }
        
        //添加学生
        public Integer add(Student student) {
            Integer code = 0;
            Object[] obj = {student.getSname(), student.getSsex(), student.getSage(), student.getScredit(),
                    student.getSmoney(), student.getSaddress(), student.getSenrol()};
            String sql = "insert into student (sname,ssex,sage,scredit,smoney,saddress,senrol) values (?,?,?,?,?,?,?) ";
            try {
                code = query.update(sql, obj);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return code;
        }
    
        //更新学生
        public Integer update(Student student) {
            Integer code = 0;
            Object[] obj = {student.getSname(), student.getSsex(), student.getSage(), student.getScredit(),
                    student.getSmoney(), student.getSaddress(), student.getSenrol(), student.getSid()};
            String sql = " update student set sname=?,ssex=?,sage=?,scredit=?,smoney=?,saddress=?,senrol=? where sid=? ";
            try {
                code = query.update(sql, obj);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return code;
        }
    
        //删除学生
        public Integer delete(Integer id) {
            Integer code = 0;
            try {
                code = query.update("delete from student where sid=?", id);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return code;
        }
    }
    Dao接口及实现类
    ##### 接口
    
    /**
     * 学生业务层Service 接口
     * @author ant
     */
    public interface StudentService {
        //查询全部学生
        List<Student> findAll();
        //查询多个学生,根据姓名和地址模糊查询
        List<Student> findByLikeNameAndLikeAddress(String name, String address);
        //查询单个学生根据id
        Student findById(Integer id);
        //查询学生总数
        Integer totalCount();
        //添加学生
        void add(Student student);
        //更新学生
        void update(Student student);
        //删除学生
        void delete(Integer id);
    }
    
    
    +++++++++++++++++++++++++++++++++++++++++
    
    ######实现类
    
    /**
     * 业务接口实现类 学生ServiceStudent
     * @author ant
     */
    public class StudentServiceImpl implements StudentService {
    
        //聚合数据操作层
        private StudentDao studentDao;
        //我们这里使用set方法,方便Spring的注入对象
        public void setStudentDao(StudentDao studentDao) {
            this.studentDao = studentDao;
        }
    
        /**
         * 注:因为下面的这些数据都是简单的CRUD操作,也没有生命业务逻辑,所以直接调用即可
         */
        //查询全部学生
        public List<Student> findAll() {
    
            return studentDao.findAll();
        }
    
        //查询多个学生,根据姓名和地址模糊查询
        public List<Student> findByLikeNameAndLikeAddress(String name, String address) {
            return studentDao.findByLikeNameAndLikeAddress(name, address);
        }
    
        //查询单个学生根据id
        public Student findById(Integer id) {
            return studentDao.findById(id);
        }
    
        //查询学生总数
        public Integer totalCount() {
            return studentDao.totalCount();
        }
    
        //添加学生
        public void add(Student student) {
            studentDao.add(student);
        }
    
        //更新学生
        public void update(Student student) {
            studentDao.update(student);
        }
    
        //删除学生
        public void delete(Integer id) {
            studentDao.delete(id);
        }
    
    }
    Service接口及实现类
    <?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
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--把C3P0连接池放入容器中-->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/demo_school"></property>
            <property name="user" value="root"></property>
            <property name="password" value="123"></property>
        </bean>
    
        <!--注册dbutils里面的QueryRunner对象-->
        <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
            <constructor-arg name="ds" ref="dataSource"></constructor-arg>
        </bean>
    
        <!--把StudentDao容器创建出来,使之聚合QueryRunner-->
        <bean id="studentDao" class="cn.xw.dao.impl.StudentDaoImpl">
            <property name="query" ref="queryRunner"></property>
        </bean>
    
        <!--把StudentService容器创建出来 并聚合StudentDao对象-->
        <bean id="studentService" class="cn.xw.service.impl.StudentServiceImpl">
            <property name="studentDao" ref="studentDao"></property>
        </bean>
    </beans>
    最重要的applicationContext.xml配置文件 基于XML的Spring
    public class Client {
        //ApplicationContext容器
        private ApplicationContext app;
        //StudentService对象
        private StudentService ss;
    
        @Before
        public void init() {
            //初始化
            app = new ClassPathXmlApplicationContext("applicationContext.xml");
            ss = app.getBean("studentService", StudentService.class);
        }
    
        @After
        public void destroy() {
            //这里没有关闭则不写了
        }
    
        @Test   //查询全部测试
        public void findAll() {
            List<Student> students = ss.findAll();
            for (Student student : students) {
                System.out.println(student);
            }
        }
    
        @Test   //模糊查询测试
        public void findByLikeNameAndLikeAddress() {
            List<Student> students = ss.findByLikeNameAndLikeAddress("张%", "%六安%");
            for (Student student : students) {
                System.out.println(student);
            }
        }
    
        @Test   //id查找测试
        public void findById() {
            Student student = ss.findById(16);
            System.out.println(student);
        }
    
        @Test   //总数查询测试
        public void totalCount() {
            Integer total = ss.totalCount();
            System.out.println("总数:" + total);
        }
    
        @Test   //添加测试
        public void add() {
            Student student = new Student(0, "王二虎", "男", 16, 55.5, 600.5, "安徽滁州", "2018-8-8");
            ss.add(student);
        }
    
        @Test   //更新测试
        public void update() {
            Student student = new Student(65, "王小二", "女", 21, 66.5, 666.5, "安徽蚌埠", "2019-8-8");
            ss.update(student);
        }
    
        @Test   //删除测试
        public void delete() {
            ss.delete(65);
        }
    }
    测试

     四:Spring之IOC详细介绍(注解版)

    1:简单的注解开发框架搭建及测试

    首先我来给大家展示一个最简单的注解搭建,后面会一步一步详解,最后会做一个案例,但是看了我下面的简单注解操作会发现很多问题,不是说注解吗?为什么还有配置文件,注入的一下方法就这么点,那注入复杂类型怎么办呢?这里等等问题后面会慢慢解决

    ####### pom.xml配置文件
    <dependencies>
            <!--导入Spring坐标-->
            <!--Spring注解开发依赖AOP包-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.6.RELEASE</version>
            </dependency>
            <!--单元测试-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
        </dependencies>
    
    
    ++++++++++++++++++++++++++++++++++++++++++
    ##### Dao接口及实现
    public interface StudentDao {
        //模拟添加学生
        void add();
    }
    
    //这里使用了Repository注解
    @Repository(value="studentDao")
    public class StudentDaoImpl implements StudentDao {
        //模拟添加学生
        public void add() {
            System.out.println("添加成功");
        }
    }
    
    
    ++++++++++++++++++++++++++++++++++++++++++
    ##### Service接口及实现类
    public interface StudentService {
        //模拟添加学生
        void add();
    }
    
    //这里使用了Service注解
    @Service(value="studentService")
    public class StudentServiceImpl implements StudentService {
        //这里使用了Autowired依赖注入
        //聚合StudentDao对象
        @Autowired
        private StudentDao studentDao;
        //添加学生
        public void add() {
            studentDao.add();
        }
    }
    
    ++++++++++++++++++++++++++++++++++++++++++
    ##### 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"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd">
    
        <!--加载配置文件后扫描指定文件夹下的注解  -->
        <context:component-scan base-package="cn.xw"></context:component-scan>
    
    </beans>
    
    
    ++++++++++++++++++++++++++++++++++++++++++
    ##### 测试
    public class Client {
        @Test   //添加测试
        public void add() {
            ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
            StudentService studentService = app.getBean("studentService", StudentService.class);
            studentService.add();
        }
    }
    完成注解的简单操作

    2:@Component注解(和XML里面的Bean一样)

      什么是@Component注解呢?大家在写XML的时候是不是使用<bean id="xx" class="xx"></bean>,是说明把指定的对象放入容器中,其实@Component注解也一样,也是告知把指定的对象放入容器中,但是注解比配置的容易,只需要把此注解写在要装入容器对象上即可,说白就是把资源让Spring管理

    @Component
    public class StudentDaoImpl implements StudentDao{
        内容省略
    }
    /**
     * 我好奇bean标签里面还有id指明以后放入容器取出的key,那这个注解也没有可咋搞?
     * 其实如果我们不写默认id是当前类的类名首字母小写 就变成了studentDaoImpl
     */
    /////////////////////////////////////////////////////////////////////////////
    /**
     * 默认的id名字太长了,所以我要给注解添加value属性,就和bean里面的id一样
     */
    @Component(value="studentDao")
    public class StudentDaoImpl implements StudentDao{
        内容省略
    }
    /////////////////////////////////////////////////////////////////////////////
    /**
     * 其实@Component 是有引申义注解的,为了让注解有个语义性,内部也做了小调整,但整体没太大差异
     * @Controller     注解表现层(Servlet)
     * @Service        注解业务层(Service)
     * @Repository     注解持久层(Dao)
     */

      @Controller(value="studentServlet")
      public class StudentServlet{}
      @Service(value="studentService")
      public class StudentServiceImpl implements StudentService{}
      @Repository(value="studentDao")
      public class StudentDaoImpl implements StudentDao{}
      @Component(value="student")
      public class Student{};

    3:注解的依赖注入(重要

    ①:@Autowired

    在注解的入门案例中,大家有发现我使用了@Autowired标签了吗?其实这就是依赖注入标签,使用特别简单,只要在需要注入数据的属性上使用此标签就好了

    @Repository(value="studentDao")
    public class StudentDaoImpl implements StudentDao{}
    
    @Service(value="studentService")
    public class StudentServiceImpl implements StudentService{
        @Autowired
        private StudentDao studentDao;
    }
    //这样我们就成功把value为studentDao的对象注入进去了  代码片段(1)

    上面的一段代码是把StudentDaoImpl对象注入进去了,可是大家发现了吗?我是怎么注入的,@Autowired没有任何标识指向上面的对象,为什么会被注入上呢?那如果我有两个StudentDaoImpl实现类后该直线谁呢?

    @Repository(value="studentDaoA")
    public class StudentDaoImplA implements StudentDao{}
    
    @Repository(value="studentDaoB")
    public class StudentDaoImplB implements StudentDao{}
    
    @Service(value="studentService")
    public class StudentServiceImpl implements StudentService{
        @Autowired
        private StudentDao studentDao;
    }
    //那这个又指向谁呢      代码片段(2)

    代码片段(1)图   由图证明是可以注入对象的

     代码片段(2)图

     根据上面2中图的第二张发现,自动注入也会有失败的,原因是多个相同类型的类和属性变量无法区分,因为Spring无法知道你具体要注入哪一个!但是针对第二张图该如何解决呢?其实很简单,只要把属性变量名改为要注入类型的知道key,比如原来是studentDao,可以key容器里面只要studentDaoA和studentDaoB,所以我们自己明确一个即可,但是Spring帮我们解决了这个修改变量名的方式,它为我们提供了一个@Qualified注解

    ①:@Qualified

    @Qualifiend注解就很好的解决了图二的问题,它内部提供value属性,让开发者手动指定对应的key用来匹配,注意,它在注解属性时必须要和@Autowired注解一起使用

    @Repository(value="studentDaoA")
    public class StudentDaoImplA implements StudentDao{}
    
    @Repository(value="studentDaoB")
    public class StudentDaoImplB implements StudentDao{}
    
    @Service(value="studentService")
    public class StudentServiceImpl implements StudentService{
        @Autowired
        @Qualifier(value = "studentDaoA")
        private StudentDao studentDao;
    }

    通过上面的标签@Autowired和@Qualified,我们知道,要使用@Qualified注解时必须搭配@Autowird注解,它们2个搭配使用可以完成注入工作,但是你们有想吗?每次都要写这么2个注解太麻烦,没有一个一步到位的标签吗?其实是有的,它就叫@Resource

    ②:@Resource

    这个注解可以说挺容易的,一步到位,我们就简单写一下它吧,然后运行

    @Service(value="studentService")
    public class StudentServiceImpl implements StudentService {
        //聚合StudentDao对象
        @Resource(name="studentDao")
        private StudentDaoImpl studentDao;
        //添加学生
        public void add() {
            studentDao.add();
        }
    }

    问题:因为我用的是jdk9版本,而jdk9就已经弃用了这个注解,还有一个和这个相同错误的就是在Spring项目中引入@Resource注解时有红色波浪线
    解决:添加对应被弃用的坐标id
    引申:@Resource这个注解位于java.xml.ws.annotation包是J2EE的一部分,但是J2EE在jdk9就被弃用了,并在JDK10删除它,可以通过查询这个包,看到里面的注解
    <dependency>
        <groupId>javax.annotation</groupId>
        <artifactId>javax.annotation-api</artifactId>
        <version>1.3.2</version>
    </dependency>

     ③:使用set方法注入

    我们前3个都是在讲为对象属性注入,而且不用set方法即可注入,那如果要用set注入该如何注入呢?

    @Service(value="studentService")
    public class StudentServiceImpl implements StudentService {
        //聚合StudentDao对象
        private StudentDaoImpl studentDao;
        //注意:使用set方法注入时在方法参数里面必须指定在容器寻找的key,
        //也就是使用@Qualifier注解指示id,这个时候注解可以单独使用,但是在属性对象中必须配合@Autoired注解
        //使用set注入数据
        public void setStudentDao(@Qualifier(value="studentDao") StudentDaoImpl studentDao) {
            this.studentDao = studentDao;
        }
      
        //添加学生
        public void add() {studentDao.add();}
    }

    ④:基本类型注入

    基本类型只有8种:int、float、double、char、long、byte、short、boolean,接下来我就争对几个来完成基本类型注入,这里注意的是引用类型只能用上面的3种方法来完成注入,这里针对的是基本类型

    //放入Spring容器
    @Component(value="myTest")
    public class MyTest {
        
        //使用Value注解依赖注入
        @Value(value="17")
        private byte age;
        @Value(value="52.6f")
        private float weight;
        @Value("6000.33")
        private double money;
        @Value("165")
        private int height;
        @Value("男")
        private char sex;
        @Value("true")
        private boolean isStudent;
    
        //打印语句
        @Override
        public String toString() {
            return "MyTest{" +
                    "age=" + age +
                    ", weight=" + weight +
                    ", money=" + money +
                    ", height=" + height +
                    ", sex=" + sex +
                    ", isStudent=" + isStudent +
                    '}';
        }
    }
    //测试
    class test{
        public static void main(String[] args) {
            ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
            MyTest test = (MyTest) app.getBean("myTest");
            System.out.println(test);
            //MyTest{age=17, weight=52.6, money=6000.33, height=165, sex=男, isStudent=true}
        }
    }
    基本类型注入

    4:改变作用范围和生命周期

     在前面的xml中介绍了如何改变容器里面的对象的作用范围,默认是单例对象;<bean id="xx" class=“xx.xx.xxx” scope="prototype"></bean>这个就是设置多例的了

    可是在注解中如何设置作用范围呢?

    @Service(value="studentService")
    @Scope(value="singleton")  //这里我设置了单例 但默认不写也是单例 多例是prototype
    public class StudentServiceImpl implements StudentService {
            ....................      
    }

    既然我们都会设置单例和多例了,可是怎么测试是单例还是多例呢?我就不比较它们的hashCode了,我这么来想,单例对象是根据容器销毁则销毁,而多例对象则由JVM垃圾回收器回收

    @Service(value="studentService")
    @Scope(value="singleton")
    public class StudentServiceImpl implements StudentService {
        //聚合StudentDao对象
        @Resource(name="studentDao")
        private StudentDaoImpl studentDao;
    
        //添加学生
        public void add() {
            studentDao.add();
        }
    
        //初始化方法
        @PostConstruct
        public void init(){
            System.out.println("初始化成功");
        }
        //销毁方法
        @PreDestroy
        public void destroy(){
            System.out.println("销毁成功");
        }
    }
    
    ++++++++++++++++++++++++++++++++++++++++++++++
     @Test   //添加测试
        public void add() {
            //因为ApplicationContext没有关闭方法,所以我们使用子类
            ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
            StudentService studentService = app.getBean("studentService", StudentService.class);
            studentService.add();
            //关闭
            app.close();
        }
    
    
    //使用xml配置方法<bean id="xxx" class="xx.xx.xx" init-method="xx" destroy-method="xxx"></bean>
    
    /*其实上面的@PostConstruct 和@PreDestroy 两个注解就相当于init-method="xx"和destroy-method="xxx"标签属性
    但是要注意的是这2个注解和@Resource注解一样必须要导入javax.annotation-api坐标,因为jdk9已经弃用了
    还有的是我们也可以使用初始化方法达到注入属性,不推荐知道就好
    //初始化方法
        @PostConstruct
        public void init(){
            studentDao=new StudentDaoImpl();
            System.out.println("初始化成功");
        }
    */
    初始化和销毁注解及测试作用范围

    5:使用注解替代XML配置文件

     ①:@Configuration@ComponentScan

    我在写注解的基本入门案例中,大家是否记得,我还是用到了xml配置文件,用来告知Spring来开启注解扫描,这显然还是在用xml配置呀,但是接下来的注解中我要彻底消除xml配置文件

    /**
     * @Configuration 注解说明当前类是一个配置类 和applicationContext.xml一样
     */
    @Configuration
    public class SpringConfig {
    
    }

    现在我们使用注解@Configuration完成了一个配置类,但是这是一个空配置类,我们要完成注解开发就要对注解扫描,就和使用xml的<context:component-scan base-package="cn.xw"></context:component-scan>一样,那我们就得使用到另一个注解@ComponentScan

    /**
     * @Configuration 注解说明当前类是一个配置类 和applicationContext.xml一样
     */
    @Configuration
    //推荐使用前五个扫描路径,其实这5个都是一样的 写法不同
    @ComponentScan("cn.xw")
    //@ComponentScan(value="cn.xw")
    //@ComponentScan(value={"cn.xw"})
    //@ComponentScan(basePackages = "cn.xw")
    //@ComponentScan(basePackages = {"cn.xw"})
    
    //扫描类的class文件 不推荐 没有扫描包方便
    //@ComponentScan(basePackageClasses ={StudentDaoImpl.class, StudentServiceImpl.class} )
    
    //设置多个路径
    // @ComponentScans(value={
    //         @ComponentScan(value="cn.xw"),
    //         @ComponentScan(value="xxx.xxx.x"),
    //         @ComponentScan("xxx.xx.xx")
    // })
    public class SpringConfig {
    
    }
    /**
     *  用于设置单个路径 @ComponentScan
     *  用于设置多个路径 @ComponentScans
     *  在查询@ComponentScan方法发现value和basePackages是一样的,为什么呢?看下面
     *     @AliasFor("basePackages")
     *     String[] value() default {};
     *     @AliasFor("value")
     *     String[] basePackages() default {};
     * @AliasFor注解在相互引用这2个方法
     */
    @ComponentScan注解详解

    6:@Bean注解的使用

      什么是@Bean注解呢?它有什么用呢?我先来举个例子,比如我们自己写的StudentDaoImpl类如果想放到Spring容器怎么办呢?其实很容易,在StudentDaoImpl类上添加一个@Repository(value="studentDao")就可以了,那么问题来了,我现在有Date、SimpleDateFormat、String三个类都想放到Spring容器中,那么大家的第一反应是直接在那个类上面添加一个注解放入Spring容器中就可以啦,但是大家想想,这3个类不是我们自己的,都是jdk提供的,而且还是class文件,我们是无法修改的,所以Spring就为我们提供了一个@Bean注解用来把初始化好的对象放入容器中,下面我就带大家看看把

      现在有个需求,要求创建一个Date对象并初始化放入容器中,SimpleDateFormat也是一样初始化好格式放入容器,最后在创建一个Spring对象返回一个格式化好的Date日期返回

    @Configuration
    @ComponentScan("cn.xw")
    public class SpringConfig {
    
        //创建一个Date对象并放入容器中 key指定为date
        @Bean(value="date")
        public Date createDate() {
            Date date = new Date(12564875956213L);
            return date;
        }
    
        //创建一个SimpleDateFormat对象放入容器中 key指示为simpleDateFormat
        @Bean(value = "simpleDateFormat")
        public SimpleDateFormat createFormat() {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
            return format;
        }
        
        //创建一个String对象放入容器 指定key为string
        //这里的方法有2个参数,具体是怎么映射上的后面说
        @Bean(value = "string")
        public String createDateString(Date time,SimpleDateFormat format){
            String dateString = format.format(time);
            return dateString;
        }
    }
    
    +++++++++++++++++++++++++++++++++++++++++
    @Test   //添加测试
    public void add() {
        ApplicationContext app=new AnnotationConfigApplicationContext(SpringConfig.class);
        String string = app.getBean("string", String.class);
        System.out.println(string); //打印结果:2368-03-02 03-19-16
    
    }
    @Bean注解解释

     注意细节:@Bean注解属性可以写name或者value,因为它们2个互相引用,执行效果都是一样的,用来标识放入IOC容器的id的key值,那么不写name或者value属性的话 默认方法名就为bean的id

     通过@Bean的介绍有个初步的了解,回到上个代码,可看出createDateString(Date time,SimpleDateFormat format)方法要求接收2个参数,可是我在上面也没指示怎么就被自动注入上了呢?其实这个原理和@Autowired自动注入一样的

    @Configuration
    @ComponentScan("cn.xw")
    public class SpringConfig {
    
        //创建一个Date对象并放入容器中 key指定为date
        @Bean(value="date")
        public Date createDate() {
            Date date = new Date(12564875956213L);
            return date;
        }
        //创建一个SimpleDateFormat对象放入容器中 key指示为simpleDateFormatA
        @Bean(value = "simpleDateFormatA")
        public SimpleDateFormat createFormatA() {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
            return format;
        }
        
        //创建一个SimpleDateFormat对象放入容器中 key指示为simpleDateFormatB
        @Bean(value = "simpleDateFormatB")
        public SimpleDateFormat createFormatB() {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return format;
        }
    
        //创建一个String对象放入容器 指定key为string
        //这里的方法有2个参数,具体是怎么映射上的后面说
        @Bean(value = "string")
        public String createDateString(Date time,@Qualifier("simpleDateFormatB") SimpleDateFormat format){
            String dateString = format.format(time);
            return dateString;
        }
    }
    
    //方法参数自动注入和属性自动注入一样,假设现在的IOC容器中只要一个SimpleDateFormat类型的,那么Spring也是很
    //智能的,直接把那个注入进去即可,因为不可能出现注入错误,但是出现两个相同类型的,Spring就没这么智能了,
    //他要我们开发者告知它准确指向
    
    //从上面的代码可以看出创建了两个SimpleDateFormat引用类型,我们就可以通过@Qualifier来指定,
    //用法在数据注入详细介绍过

    7:获取注解容器

      细心的人肯定会发现 我在去除ApplicationContext.xml配置文件后的测试类都使用了AnnotationConfigApplicationContext,原因是现在配置文件都是注解的了,再使用ClassPathXmlApplicationContext就获取不到指定的配置类了,下面我给大家介绍一下

    @Test   //添加测试
    public void add() {
        //获取注解类
        ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class);
        String string = app.getBean("string", String.class);
        System.out.println(string);
        /**
         * ApplicationContext常见的获取容器子类有3个 在ApplicationContext接口的实现类有介绍前2个
         * AnnotationConfigApplicationContext:用来加载读取配置类,用来读取注解配置类、
         * 参数可以是伪数组
         */
    }

    获取规则(重要):如果参数直接写到指定的配置类上的class,那个类可以不需要指定@Configuration注解,如果多个类都指定@Configuration注解,那么在获取这些配置类的时候要把全部的class类通过伪数组放入方法参数中。如果配置类过多可以在指定一个主配置类上面标注@Configuration注解,其它的子类可以不指定@Configuration注解,但是在主配置类上要使用@Import注解来引用子配置类。

    //主配置类 引用l子配置类
    @Configuration
    @ComponentScan("cn.xw")
    @Import(value={SpringConfigB.class,SpringConfigD.class})
    public class SpringConfig {
    
    }
    //子配置类
    class SpringConfigB{}
    //子配置类
    class SpringConfigD{}

    8:获取配置文件数据

    配置数据文件我相信大家在写连接数据库的四大数据了经常用到,可是在注解中怎么获取配置连接数据呢?,接下来我就为大家来演示一个常用的操作

    <!--Mysql驱动坐标-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.30</version>
            </dependency>
            <!--C3P0连接池坐标-->
            <dependency>
                <groupId>c3p0</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.1.2</version>
            </dependency>
    导入2个坐标
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/demo_school
    jdbc.username=root
    jdbc.password=123
    dataSource.properties配置文件
    @Configuration
    @ComponentScan("cn.xw")
    @PropertySource("classpath:dataSource.properties")
    public class SpringConfig {
        
        //注入下面4个属性 单个value可以省去直接写值
        @Value(value = "${jdbc.driver}")
        private String driver;
        @Value(value = "${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
        
        @Bean(value="dataSource")
        public DataSource createDataSourcePool() {
            //创建C3P0连接池
            ComboPooledDataSource ds = new ComboPooledDataSource();
            try {
                //设置连接池
                ds.setDriverClass(driver);
                ds.setJdbcUrl(url);
                ds.setUser(username);
                ds.setPassword(password);
            } catch (PropertyVetoException e) {
                e.printStackTrace();
            }
            return ds;
        }
    }

    注:@PropertySource注解是配置类路径下文件,还有一个@PropertySources注解是配置多个,里面可以写多个@PropertySource,和@ComponentScans一样写法格式

    9:Spring整合Junit测试(重要

    我们在前面的时候写测试类都是使用ApplicationContext app=new xxxx(xxx);这样的写法无疑使程序测试变的麻烦,那我们就不能对对属性进行注入然后运行吗,就像下面的这段代码操作

    public class Client {
        //属性注入
        @Autowired
        @Qualifier(value = "studentService")
        private StudentService ss;
    
        @Test   //添加测试
        public void add() {
            //调用保存方法
            ss.add();
        }
    }

      大家看上面的一段代码也没什么错,正常的注入,然后调用Service方法,可是程序在运行的时候抛了一个空指针异常,而且还是明确在ss.add()这一行,那就说明了StudentService属性压根就没有注入上,为什么呢?你们首先想一想,我之前在运行测试的时候会执行到ApplicationContext app=new xxx(xxx),这句话一执行就会找到那个配置文件/配置类,然后读取那个配置文件后,把读取到的数据放到一个IOC容器中,这样我们在后面使用依赖注入的时候就可以去IOC容器取到相对于的类型,可是现在我们把那个ApplicationContext app=new xxx(xxxx)去除了,肯定就找不到了,那么怎么办呢?其实我们需要的是程序能为我们自动创建容器,一旦程序可以自动帮我们创建了容器,那么我们的问题也就解决了。

      其实junit是无法实现帮我们自动创建IOC容器的,因为它的管理范畴就是单单的测试,而且它压根也就不知道你使用的是Spring框架,更别说创建容器了,但是好在junit为外界提供了一个注解,可以让我们指定替换掉它的运行器,这时候我们就要把Spring框架的test的jar包里的SpringJUnit4ClassRunner类放入到运行器中替换,这样就完成了有Spring管理junit了。

    <!--Spring的测试坐标-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.2.6.RELEASE</version>
            </dependency>
    <!--单元测试-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
    
    <!--maven导入Spring-test坐标必须要导入junit坐标,而且导入Spring-test坐标的话,junit坐标必须为4.1.2或以上-->
    导入对应坐标
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringConfig.class) //用于指示注解类位置
    //@ContextConfiguration(locations = "classpath:applicationContext.xml") //用于指示配置文件为了 类路径下
    public class Client {
        //属性注入
        @Autowired
        @Qualifier(value = "studentService")
        private StudentService ss;
    
        @Test   //添加测试
        public void add() {
            //调用保存方法
            ss.add();
        }
    }
    /**
     * @RunWith(SpringJUnit4ClassRunner.class)
     * 更改运行器,交由Spring管理Junit
     * 
     * @ContextConfiguration(classes = SpringConfig.class)
     * 告知Spring我们的配置文件/配置类放到哪了
     */

    10:注解开发总结案例对学生单表CRUD操作

     在学习完前面的注解知识后,我接下来就带大家完成一个纯注解的CRUD操作,还是和XML的总结案例一样,也是那几个技术,mysql建表语句也是和之前的一样。

    <dependencies>
            <!--mysql驱动坐标-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.32</version>
            </dependency>
    
            <!--c3p0连接池坐标-->
            <dependency>
                <groupId>c3p0</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.1.2</version>
            </dependency>
    
            <!--dbutils工具类坐标-->
            <dependency>
                <groupId>commons-dbutils</groupId>
                <artifactId>commons-dbutils</artifactId>
                <version>1.7</version>
            </dependency>
    
            <!--junit单元测试坐标-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
    
            <!--Spring-context主要坐标-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.6.RELEASE</version>
            </dependency>
    
            <!--Spring-test测试坐标-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.2.6.RELEASE</version>
            </dependency>
    
            <!--annotation坐标-->
            <dependency>
                <groupId>javax.annotation</groupId>
                <artifactId>javax.annotation-api</artifactId>
                <version>1.3.2</version>
            </dependency>
        </dependencies>
    pom.xml坐标文件
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/demo_school
    jdbc.username=root
    jdbc.password=123
    jdbc.properties数据库连接资源文件
    public class Student {
    
        private int sid;            //主键id
        private String sname;       //姓名
        private String ssex;        //性别
        private int sage;           //年龄
        private double scredit;     //学分
        private double smoney;      //零花钱
        private String saddress;    //住址
        private String senrol;      //入学时间
        //因为简单的单表CRUD就不涉及到外键
        //private int fid;            //外键 连接家庭表信息学生对家庭,一对一
        //private int tid;            //外键 连接老师信息 学生对老师,一对一
        //创建构造器/get/set/toString就不展示了
    }
    Student实体类
    //当前是主配置类
    @Configuration
    @ComponentScan(value = "cn.xw")
    @Import(value={DataSourceConfig.class})
    public class SpringConfig {
    
        //创建对象QueryRunner放入IOC容器  因为连接QueryRunner有多个操作 所以设置多例
        @Bean("queryRunner")
        @Scope(value = "prototype")
        public QueryRunner createQueryRunner(@Qualifier("dataSource") DataSource dataSource) {
            QueryRunner queryRunner=new QueryRunner(dataSource);
            return queryRunner;
        }
    }
    
    +++++++++++++++++++++++++++++++++++++++++
    
    //获取配置文件注解
    @PropertySource("classpath:jdbc.properties")
    public class DataSourceConfig {
    
        //注入数据从配置文件获取四大数据
        @Value("${jdbc.driver}")
        private String driver;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
    
        //创建c3p0连接池并返回一个DataSource
        @Bean("dataSource")
        public DataSource createDataSource() {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            try {
                ds.setDriverClass(driver);
                ds.setJdbcUrl(url);
                ds.setUser(username);
                ds.setPassword(password);
            } catch (PropertyVetoException e) {
                e.printStackTrace();
            }
            return ds;
        }
    }
    配置类两个(其中一个主配置类)
    /**
     * 学生数据操作Dao接口
     * @author ant
     */
    public interface StudentDao {
        //查询全部学生
        List<Student> findAll();
        //查询多个学生,根据姓名和地址模糊查询
        List<Student> findByLikeNameAndLikeAddress(String name, String address);
        //查询单个学生根据id
        Student findById(Integer id);
        //查询学生总数
        Integer totalCount();
        //添加学生
        Integer add(Student student);
        //更新学生
        Integer update(Student student);
        //删除学生
        Integer delete(Integer id);
    }
    
    
    
    +++++++++++++++++++++++++++++++++++++++++
    
    /**
     * 学生数据操作Dao实现类
     * @author ant
     */
    @Repository("studentDao")
    public class StudentDaoImpl implements StudentDao {
        //聚合dbutils工具类
        @Resource(name = "queryRunner")
        private QueryRunner query;
    
        //查询全部学生
        public List<Student> findAll() {
            //初始化查询后封装的数据变量
            List<Student> students = null;
            //Sql语句
            String sql = "select * from student";
            //异常处理
            try {
                //执行sql语句并查询数据
                students = query.query(sql, new BeanListHandler<Student>(Student.class));
            } catch (SQLException e) {
                e.printStackTrace();
            }
            //返回数据
            return students;
        }
    
        //查询多个学生,根据姓名和地址模糊查询
        public List<Student> findByLikeNameAndLikeAddress(String name, String address) {
            List<Student> students = null;
            String sql = "select * from student where sname like ? and saddress like ? ";
            try {
                students = query.query(sql, new BeanListHandler<Student>(Student.class), name, address);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return students;
        }
    
        //查询单个学生根据id
        public Student findById(Integer id) {
            Student student = null;
            try {
                student = query.query("select * from student where sid=?", new BeanHandler<Student>(Student.class), id);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return student;
        }
        //查询学生总数
        public Integer totalCount() {
            Integer total = 0;
            try {
                total = Integer.parseInt(query.query("select count(sid) from student", new ScalarHandler<Object>()).toString());
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return total;
        }
        //添加学生
        public Integer add(Student student) {
            Integer code = 0;
            Object[] obj = {student.getSname(), student.getSsex(), student.getSage(), student.getScredit(),
                    student.getSmoney(), student.getSaddress(), student.getSenrol()};
            String sql = "insert into student (sname,ssex,sage,scredit,smoney,saddress,senrol) values (?,?,?,?,?,?,?) ";
            try {
                code = query.update(sql, obj);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return code;
        }
        //更新学生
        public Integer update(Student student) {
            Integer code = 0;
            Object[] obj = {student.getSname(), student.getSsex(), student.getSage(), student.getScredit(),
                    student.getSmoney(), student.getSaddress(), student.getSenrol(), student.getSid()};
            String sql = " update student set sname=?,ssex=?,sage=?,scredit=?,smoney=?,saddress=?,senrol=? where sid=? ";
            try {
                code = query.update(sql, obj);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return code;
        }
        //删除学生
        public Integer delete(Integer id) {
            Integer code = 0;
            try {
                code = query.update("delete from student where sid=?", id);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return code;
        }
    }
    dao数据操作接口及实现类
    /**
     * 学生业务层Service 接口
     * @author ant
     */
    public interface StudentService {
        //查询全部学生
        List<Student> findAll();
        //查询多个学生,根据姓名和地址模糊查询
        List<Student> findByLikeNameAndLikeAddress(String name, String address);
        //查询单个学生根据id
        Student findById(Integer id);
        //查询学生总数
        Integer totalCount();
        //添加学生
        void add(Student student);
        //更新学生
        void update(Student student);
        //删除学生
        void delete(Integer id);
    }
    
    +++++++++++++++++++++++++++++++++++++++++
    
    /**
     * 业务接口实现类 学生ServiceStudent
     * @author ant
     */
    @Service("studentService")
    public class StudentServiceImpl implements StudentService {
        //聚合数据操作层
        @Autowired
        @Qualifier("studentDao")
        private StudentDao studentDao;
    
        /**
         * 注:因为下面的这些数据都是简单的CRUD操作,也没有生命业务逻辑,所以直接调用即可
         */
        //查询全部学生
        public List<Student> findAll() {
            return studentDao.findAll();
        }
        //查询多个学生,根据姓名和地址模糊查询
        public List<Student> findByLikeNameAndLikeAddress(String name, String address) {
            return studentDao.findByLikeNameAndLikeAddress(name, address);
        }
        //查询单个学生根据id
        public Student findById(Integer id) {
            return studentDao.findById(id);
        }
        //查询学生总数
        public Integer totalCount() {
            return studentDao.totalCount();
        }
        //添加学生
        public void add(Student student) {
            studentDao.add(student);
        }
        //更新学生
        public void update(Student student) {
            studentDao.update(student);
        }
        //删除学生
        public void delete(Integer id) {
            studentDao.delete(id);
        }
    }
    service业务处理接口级实现类
    //设置运行器和配置类位置
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = SpringConfig.class)
    public class Client {
        //注解注入
        @Autowired
        @Qualifier(value="studentService")
        private StudentService ss;
    
        @Test   //查询全部测试
        public void findAll() {
            List<Student> students = ss.findAll();
            for (Student student : students) {
                System.out.println(student);
            }
        }
        @Test   //模糊查询测试
        public void findByLikeNameAndLikeAddress() {
            List<Student> students = ss.findByLikeNameAndLikeAddress("张%", "%六安%");
            for (Student student : students) {
                System.out.println(student);
            }
        }
        @Test   //id查找测试
        public void findById() {
            Student student = ss.findById(16);
            System.out.println(student);
        }
        @Test   //总数查询测试
        public void totalCount() {
            Integer total = ss.totalCount();
            System.out.println("总数:" + total);
        }
        @Test   //添加测试
        public void add() {
            Student student = new Student(0, "王二虎", "男", 16, 55.5, 600.5, "安徽滁州", "2018-8-8");
            ss.add(student);
        }
        @Test   //更新测试
        public void update() {
            Student student = new Student(65, "王小二", "女", 21, 66.5, 666.5, "安徽蚌埠", "2019-8-8");
            ss.update(student);
        }
        @Test   //删除测试
        public void delete() {
            ss.delete(65);
        }
    }
    测试类 Spring整合Junit

    五:Spring IOC 总结

      在学了上面的Spring IOC后,知道了Spring IOC为了程序解耦,使用过XML和注解两种方法完成表的CRUD操作,可是这个两个有什么优势呢?或者说哪个更好呢?其实2个都差不多,xml配置是文件更清晰可见,但是特别繁琐,一大段一大段的标签要写,好多都是重复性的写标签,但是注解开发呢,使效率上有提高,但是呢,如果大量的使用注解后使程序的可读性变差;比如在类上面使用注解,使之放到IOC容器中,这样如果出现多个类后,后期要查看当前类是否有放入容器中,只要点卡此类查看,但是使用xml呢?我直接新建一个xml专门存放要存放容器的对象,这样清晰可读,所以总结一下使用注解和xml搭配使用会有好的效果!

  • 相关阅读:
    基于Metaweblog API 接口一键发布到国内外主流博客平台
    uva144 Student Grants
    Uva 10452
    Uva 439 Knight Moves
    Uva 352 The Seasonal War
    switch语句
    java——基础知识
    我的lua学习2
    codeforces 431 D. Random Task 组合数学
    codeforces 285 D. Permutation Sum 状压 dfs打表
  • 原文地址:https://www.cnblogs.com/antLaddie/p/12813409.html
Copyright © 2011-2022 走看看