• 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搭配使用会有好的效果!

  • 相关阅读:
    svn备份
    Java Web开发引用包的方法
    nucht1.2二次开发增量采集
    程序集信息设置.net
    lucene的基本查询及lucene3.0.1API
    Asp.net网站部署
    C语言面试算法题(一)
    面试题
    C语言面试算法题(二)
    C++的IO流的函数
  • 原文地址:https://www.cnblogs.com/antLaddie/p/12813409.html
Copyright © 2020-2023  润新知