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可以指定对象是单实例还是多实例的!













  • 相关阅读:
    城市的划入划出效果
    文本溢出省略解决笔记css
    长串英文数字强制折行解决办法css
    Poj 2352 Star
    树状数组(Binary Indexed Trees,二分索引树)
    二叉树的层次遍历
    Uva 107 The Cat in the Hat
    Uva 10336 Rank the Languages
    Uva 536 Tree Recovery
    Uva10701 Pre, in and post
  • 原文地址:https://www.cnblogs.com/bkyy/p/8006937.html
Copyright © 2011-2022 走看看