zoukankan      html  css  js  c++  java
  • Spring && 实验IOC

    一、Spring作用

        1.生态体系庞大,全能型选手!【springmvc是其一个子模块,jdbcTemplate能直接操作数据库!】
        2.将其他组件粘合在一起
        3.IOC容器和AOP[Aspect Oreinted Programming]:
            Spring的Ioc[Inverse of Controller]机制(控制反转和依赖注入)正是用在此处。
            Spring的Ioc(控制反转和依赖注入)
                 控制反转[Ioc]:就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直接操控。
                 控制反转是一种思想,其具体实现就是依赖注入!
                 依赖注入[DI:Dependency Injection]:组件之间的依赖关系由容器在运行期决定,由容器动态的将某种依赖关系注入到组件之中。

    二、搭建Spring IOC容器需要的开发环境

       1.导入IOC容器需要的jar包
            spring-beans-4.0.0.RELEASE.jar
            spring-context-4.0.0.RELEASE.jar
            spring-core-4.0.0.RELEASE.jar
            spring-expression-4.0.0.RELEASE.jar
            commons-logging-1.1.3.jar
       2.创建Spring配置文件[Spring bean Configuration File]
            applicationContext.xml
      

    三、IOC容器创建对象步骤

        1.创建IOC容器对象
                private ApplicationContext ioc=new FileSystemXmlApplicationContext("C:\Users\Administrator\Desktop\applicationContext.xml"); //本地文件系统(磁盘)
               * private ApplicationContext ioc1=new ClassPathXmlApplicationContext("applicationContext.xml"); //src下
        
        2.使用IOC容器在创建对象的同时,给对象的属性赋值
       
           从IOC容器中获取对象就两种方式:1、通过id值获取bean对象
                          2、通过IOC容器中bean的类型获取bean对象

       <!--实验1:通过IOC容器创建对象,并为属性赋值  -->
        <!-- 需要由IOC容器创建对象的全类名 -->
        <!-- 为了便于从IOC容器中获取book对象,声明一个一个唯一的id值 -->
       <bean id="book01" class="com.neuedu.spring.bean.Book">
            <property name="bookId" value="2001"></property>
            <property name="bookName" value="三国演义"></property>
            <property name="author" value="罗贯中"></property>
            <property name="price" value="22.5"></property>
        </bean>
    View Code
     @Test
            public void test01() {
                //1.创建IOC容器自身的对象
                //指定配置文件以类路径为基准的配置文件名
                ApplicationContext ioc= new ClassPathXmlApplicationContext("bean.xml");
                //2.从IOC容器中获取指定的对象
                Object bean = ioc.getBean("book01");
                System.out.println(bean);
            }
    View Code

    注意:
        ①IOC容器本身对象创建时,会将配置文件中配置好的bean先创建出来
        ②默认是单实例的,只创建bean的一个对象
        ③如果设置bean的scope属性为prototype,那么创建bean的对象就是多实例的,在获取的时候创建,每次获取对象都会创建新的
        ④.从IOC容器中获取对象
            ①根据bean的id获取
            ②根据bean的类型获取:要求容器中指定类型的bean是唯一的

    bean的后置处理器:
        1.指的是在bean的初始化方法前后执行操作的专门的对象。
        2.自定义的后置处理器:
            1)需要实现接口:org.springframework.beans.factory.config.BeanPostProcessor .
            2) 做相应的配置就好!
       

       <!-- bean的后置处理器 -->
         <bean id="beanPostProcessor" class="com.neuedu.entity.MyBeanPostProcessor"></bean>
       
    package com.neuedu.entity;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class MyBeanPostProcessor implements BeanPostProcessor{
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName)
                throws BeansException {
            System.out.println("===================================");
            System.out.println("BeforeInitialization:"+beanName+"="+bean);
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName)
                throws BeansException {
            System.out.println("=============================");  
            System.out.println("AfterInitialization:"+beanName+"="+bean);
            return bean;
        }
    
         
    }
    View Code
            /*bean的后置处理器*/
        @Test
        public void test02() {
             Object bean = ioc.getBean("beanPostProcessor");
             System.out.println(bean);
        }            
    View Code



    配置FactoryBean★ 

        public class MyFactoryBean implements FactoryBean<Book> {
    
            @Override
            public Book getObject() throws Exception {
                return new Book(22, "无字天书", "好啊", 22.5);
            }
    
            @Override
            public Class<?> getObjectType() {
                return Book.class;
            }
    
            @Override
            public boolean isSingleton() {
                return false;
            }
    
        }
    

    测试bean的作用域,分别创建单实例和多实例的bean★

       <!-- scope属性为prototype,那么创建bean的对象就是多实例的 -->
       <bean id="user" class="com.neuedu.entity.User" scope="prototype">
               <property name="id" value="user01"/>
               <property name="name" value="Danny"/>
               <property name="age" value="23"/>
       </bean>
       <!-- scope属性为singleton为默认值,默认是单实例的,只创建bean的一个对象 -->
       <bean id="user" class="com.neuedu.entity.User" scope="singleton">
               <property name="id" value="user01"/>
               <property name="name" value="Danny"/>
               <property name="age" value="23"/>
       </bean>
    

     
    实验22:创建带有生命周期方法的bean

      <!--创建带有生命周期方法的bean -->
       <bean id="lifeObject" class="com.neuedu.entity.LifeObject" init-method="initMethod" destroy-method="destroyMethod" />
    

     
    实验22[补充]:测试bean的后置处理器
        ①在bean的初始化方法调用前后执行操作的专门的对象
        ②自定义后置处理器实现该接口:org.springframework.beans.factory.config.BeanPostProcessor
        ③在springmvc中配置一下该bean对象.
        <bean class="com.neuedu.spring.bean.Book" init-method="init"></bean>
        <bean id="myBeanPostProcessor" class="com.neuedu.spring.bean.MyBeanPostProcessor"></bean>
        
        批处理(batch)
            - 批处理指的是一次操作中执行多条SQL语句
            - 批处理相比于一次一次执行效率会提高很多
            
            - 批处理主要是分两步:
                1.将要执行的SQL语句保存
                2.执行SQL语句
                
            - Statement和PreparedStatement都支持批处理操作,这里我们只需要掌握PreparedStatement的批处理方式:
                - 方法:
                    void addBatch()
                        - 将要执行的SQL先保存起来,先不执行
                        - 这个方法在设置完所有的占位符之后调用
                    int[] executeBatch()
                        - 这个方法用来执行SQL语句,这个方法会将批处理中所有SQL语句执行
                        
            - mysql默认批处理是关闭的,所以我们还需要去打开mysql的批处理:
                ?    rewriteBatchedStatements=true
                我们需要将以上的参数添加到mysql的url地址中
                
            - 注意:低版本的mysql-jdbc驱动也不支持批处理
            

            
    事务(Transaction)
            - 在开发中我们的一个业务往往需要同时操作多个表,这些操作往往是不可分割,业务中的对数据库的多次操作,
                要么同时成功,要么全都失败。
            - 注意:我们在同一个事务中使用的数据库连接(Connection)必须是同一个。    

            - 事务的特性(ACID):
                  原子性(atomicity)
                        一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
                    
                   一致性(consistency)
                         事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

                   隔离性(isolation)
                          一个事务的执行不能被其他事务干扰。
                              即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
                        
                  持久性(durability)
                         持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久。 接下来的其他操作或故障不应该对其有任何影响。
                        
            - 操作失误的基本步骤:
                  1.开启事务
                      - 开启事务以后,我们只后的所有操作将都会在同一个事务当中
                  2.操作数据库
                      - 开启事务以后再去操作数据库,所有操作将不会直接提交到数据库中
                  3.提交事务
                      - 将修改应用到数据库
                  4.回滚事务
                      - 数据库操作过程中出现异常了,回滚事务,回滚事务以后,数据库变成开启事务之前的状态
            
                - mysql中的事务控制
                    #开启事务
                    START TRANSACTION
                
                    #回滚事务
                    ROLLBACK
                
                    #提交事务
                    COMMIT
                
            - JDBC中的事务主要通过Connection对象来控制的
                1.开启事务
                    void setAutoCommit(boolean autoCommit) throws SQLException;
                    - 设置事务是否自动提交,默认是自动提交
                    - 设置事务手动提交
                        conn.setAutoCommit(false);
                    
                2.提交事务
                    void commit() throws SQLException;
                    - 提交事务
                    conn.commit()
                
                3.回滚事务
                    void rollback() throws SQLException;
                    - 回滚事务
                    conn.rollback()
                    
            - 事务控制的格式:
             

               //创建一个Connection
                Connection conn = null;
                
                try{
                    
                    //获取Connection
                    conn = JDBCUtils.getConnection();
                    
                    //开启事务
                    conn.setAutoCommit(false);
                    
                    //对数据库进行操作
                    
                    //操作成功,提交事务
                    conn.commit();
                    
                }catch(Exception e){
                    e.printStackTrace();
                    
                    //回滚事务
                    try {
                        conn.rollback();
                    } catch (SQLException e1) {
                        e1.printStackTrace();
                    }
                    
                }finally{
                    JDBCUtils.close(conn, null, null);
                }
    
        
    


    数据库连接池:
        6) 数据库连接池
            > 数据库连接池就是存放数据库连接(Connection)的集合
            > 我们获取一个数据库连接是一个相对很麻烦的过程,
                如果我们获取一个数据库连接,使用一次以后就给它关闭了
                    下一次再去使用的时候就要重新创建一个新的数据库连接。
            > 所以我们提出了一个数据库连接池的概念,数据库连接池放的都是数据库连接(Connection)
                我们在去使用数据库连接时候,不用再去重新创建数据库连接,而是直接从池中获取,
                    使用完的数据库连接,也不是直接销毁,而是要放回到连接池。
            > 数据库连接池的常见的属性:
            
                ?    初始连接数量:数据连接池创建以后,保存数据库连接的数量
                
                ?    最小空闲连接数:数据库连接池最少得未使用的数据库连接的数量
                
                    最大空闲连接数:数据库连接池最大闲置连接数,当闲置连接数满了以后,将不会有其他连接进入池
                
                ?    每次增加连接数:当数据库连接都被占用以后,一次性增加的数据库连接的个数

                ?    最大连接数:数据库连接池的最大容量,当最大连接数饱和了,则不再创建新的数据库连接
                
                ?    最大等待时间:当数据库连接池饱和以后,等待获取数据库连接的时间
                
            > 常见的数据库连接池
                - 所有的数据库连接池都需要实现DataSource,当使用数据库连接池是,我们便不再需要使用DriverManger获取数据库连接
                    而是使用DataSource。
                     - Connection getConnection()
                        - 从数据库连接池中获取数据库连接对象

                1.DBCP
                    - DBCP是Apache出品的一款数据库连接
                    - DBCP依赖于commons-pool
                    - 使用DBCP需要导入两个jar包:
                        commons-dbcp-1.4.jar
                        commons-pool-1.5.5.jar
                    - 当我们通过数据库连接池获取数据库连接以后,我们所获取到数据库连接已经不是我们熟悉的那个Connection
                        数据库连接池对Connection对象进行了包装,它修改Connection的close()方法,
                            再去调用close()数据库连接将不会真的关闭,而是要放回到数据库连接池中,供其他线程使用。
                    - 核心类:
                        BasicDataSourceFactory
                
                
                2.C3P0(重点)
                    - C3P0使用的是XML作为配置文件
                    - 使用c3p0需要导入一个jar包:
                        c3p0-0.9.1.2.jar
                    - 导入c3p0的配置文件:
                        1.配置文件的名字:c3p0-cofig.xml
                        2.配置文件要求放到类路径下(src)
                    - 核心类:    
                        ComboPooledDataSource
                    - 注意:
                        DataSource就相当于池子,我们的数据库连接都是从DataSource中获取的,
                            如果程序中有多个DataSource的实例,那么我们说你还不如不用数据库连接池。
                        所以我们的DataSource在项目中应该只有一个实例。


                        
                    
    实验23:引用外部属性文件★
           jdbc.properties文件:
            jdbc.user=root
            jdbc.passowrd=123456
            jdbc.url=jdbc:mysql://localhost:3306/test
            jdbc.driver=com.mysql.jdbc.Driver
            
        <context:property-placeholder location="classpath:jdbc.properties"/>
        1.在目标属性上加@Value注解
            @Value("${jdbc.user}")
            private String username;
        2.    
            <!-- 根据外部属性文件中的信息配置数据源 -->
            <bean id="comboPooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
                <property name="user" value="${jdbc.user}"></property>
                <property name="password" value="${jdbc.passowrd}"></property>
                <property name="jdbcUrl" value="${jdbc.url}"></property>
                <property name="driverClass" value="${jdbc.driver}"></property>
            </bean>
            
            
            ComboPooledDataSource bean = ioc.getBean(ComboPooledDataSource.class);
            Connection connection = bean.getConnection();
            System.out.println(connection);
            Statement st = connection.createStatement();
            ResultSet rs = st.executeQuery("select * from stu");
            while(rs.next()){
                String string = rs.getString("name");
                String string2 = rs.getString("school");
                System.out.println(string+"==="+string2);
            }
            

    实验24:基于XML的属性装配
        ①手动装配
            <!-- 属性的装配:手动装配 -->
            <bean id="userService" class="com.neuedu.spring.bean.UserService"></bean>
            <bean  id="userAction" class="com.neuedu.spring.bean.UserAction">
                <property name="userService" ref="userService"></property>
            </bean>
            
        ②自动装配
            <!-- 1.按类型装配:byType -->
                <!-- 首先检测当前bean中需要装配的属性的类型 -->
                <!-- 然后在IOC容器中查找匹配这个类型的bean -->
                <!-- 如果类型匹配的bean是唯一的,那么就将这个匹配的bean注入到userAction中 -->
                    
                    <bean id="userService" class="com.neuedu.spring.bean.UserService"></bean>
                    <bean  id="userAction" autowire="byType" class="com.neuedu.spring.bean.UserAction"></bean>
        
            <!-- 2.按bean的id值装配:byName -->
                <!-- 首先检测当前bean中需要装配的属性的属性名,属性名是将setXxx()方法去掉set,首字母小写得到的 -->
                <!-- 然后根据属性名作为id的值,在IOC容器中查找对应的bean -->
                <!-- 如果能够找到,则将找到bean注入进去 -->
            
            
            
    6。SpEL简介【见WORLD文档---了解】
        Spring Expression Language,Spring表达式语言,简称SpEL。支持运行时查询并可以操作对象图。
        和JSP页面上的EL表达式、Struts2中用到的OGNL表达式一样,SpEL根据JavaBean风格的getXxx()、setXxx()方法定义的属性访问对象图,完全符合我们熟悉的操作习惯。
        
        6.1    基本语法
            SpEL使用#{…}作为定界符,所有在大框号中的字符都将被认为是SpEL表达式。
            
        6.2    使用字面量
            ●整数:<property name="count" value="#{5}"/>
            ●小数:<property name="frequency" value="#{89.7}"/>
            ●科学计数法:<property name="capacity" value="#{1e4}"/>
            ●String类型的字面量可以使用单引号或者双引号作为字符串的定界符号
                <property name=“name” value="#{'Chuck'}"/>
                <property name='name' value='#{"Chuck"}'/>
            ●Boolean:<property name="enabled" value="#{false}"/>

        
    实验25:[SpEL测试I]在SpEL中使用字面量
    实验26:[SpEL测试II]在SpEL中引用其他bean
    实验27:[SpEL测试III]在SpEL中引用其他bean的某个属性值
    实验28:[SpEL测试IV]在SpEL中调用非静态方法
    实验29:[SpEL测试V]在SpEL中调用静态方法
    实验30:[SpEL测试VI]在SpEL中使用运算符

    8.使用注解配置bean
        ①声明bean的注解
            @Component 将当前类声明为IOC容器中的一个普通的组件
            @Controller 将当前类声明为IOC容器中的一个控制器组件
            @Service 将当前类声明为IOC容器中的业务逻辑层组件
            @Repository 将当前类声明为IOC容器中的一个持久化层组件
        Spring根据上述注解其实并不能分辨当前类是否真的是一个控制器或Dao,即使标记的类和注解不对应也没有语法错误。但在实际工作中,肯定要将专门的注解标记在对应的类上面。
        
        ②使用基于注解的bean的配置,需要额外导入一个jar包:spring-aop-4.0.0.RELEASE.jar
        ③需要设置自动扫描的包
            < context:component-scan base-package ="com.neuedu.ioc.bean"/>

            
        ④使用注解后,默认按照类名首字母小写作为id的值,也可以使用value属性指定id,value属性名也可以省略注解        
            注解                                           id值
        
            @Component                                    commonComponent
            public class CommonComponent {
            }
       
           @Controller(value="neueduBookAction" )         neueduBookAction
            public class BookAction {

            }
            
            @Service("happyService" )                     happyService
            public class BookService {

            }
        
        
    实验31:通过注解分别创建Dao、Service、Controller★    
        
    实验32:使用context:include-filter指定扫描包时要包含的类
    实验33:使用context:exclude-filter指定扫描包时不包含的类

    < context:component-scan base-package ="com.neuedu.ioc.bean"/>    
        [1]base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包及其子包中的所有类。
        [2]当需要扫描多个包时可以使用逗号分隔,
        [3]如果仅希望扫描特定的类而非基包下的所有类,可使用resource-pattern属性过滤特定的类,示例:
            <context:component-scan base-package="com.neuedu.component" resource-pattern="autowire/*.class"/>
        [4]包含与排除
            ●<context:include-filter>子节点表示要包含的目标类
                注意:通常需要与use-default-filters属性配合使用才能够达到“仅包含某些组件”这样的效果。
                即:通过将use-default-filters属性设置为false,禁用默认过滤器,然后扫描的就只是include-filter中的规则
                指定的组件了。
            ●<context:exclude-filter>子节点表示要排除在外的目标类
            ●component-scan下可以拥有若干个include-filter和exclude-filter子节


            
    ⑤使用注解进行自动装配:@Autowired注解[好处就是:连get、set方法都不用写!]
        [1]首先检测标记了@Autowired注解的属性的类型
        [2]根据类型进行装配
        [3]如果指定类型的bean不止一个,那么根据需要被装配的属性的属性名做id的值,查找bean
        [4]如果根据id值还是没有找到bean,可以使用@Qualifier注解手动指定要装配的bean的id.
        
    实验34:使用@Autowired注解实现根据类型实现自动装配★
    实验34[补充1]:如果资源类型的bean不止一个,默认根据@Autowired注解标记的成员变量名作为id查找bean,进行装配★
    实验34[补充2]:如果根据成员变量名作为id还是找不到bean,可以使用@Qualifier注解明确指定目标bean的id★
    实验36:Autowired注解的required属性指定某个属性允许不被设置.
    实验37:在类上使用注解@Scope可以指定对象是单实例还是多实例的!













  • 相关阅读:
    【hive】时间段为五分钟的统计
    【git】提交到github不显示贡献小绿点问题的解决
    【hive】关于用户留存率的计算
    【hive】求日期是星期几
    【hive】数据仓库层次设计
    【hive】count() count(if) count(distinct if) sum(if)的区别
    转载:几种 hive join 类型简介
    丑小鸭和白天鹅没有区别
    好好照顾自己,就像照顾你爱的人那样;
    灵光一闪(最近更新于2020/8/23)
  • 原文地址:https://www.cnblogs.com/bkyy/p/8006937.html
Copyright © 2011-2022 走看看