spring

头像
    阅读 7 分钟

    一、Spring简介
    1、什么是Spring

    Spring是一个用于简化企业级Java开发的应用框架
    Spring以 IoC(控制反转)和 AOP(面向切面编程)为核心,提供了表现层的SpringMVC支持,也提供了业务层的声明式事务支持,以及提供了持久层的JdbcTemplate支持。Spring除了自身所提供的功能外,还可以作为一个粘合剂,用于整合优秀的第三方技术框架。
    SSH(spring整合Struts2、spring整合Hibernate)
    SSH(spring整合SpringMVC、spring整合Mybatis)
    

    2、Spring的优势

    1)方便解耦,简化开发
    2)提供了AOP、声明式事务支持(后面阶段讲解)
    3)对JavaEE进行了封装,降低开发难度
    。。。
    

    二、Spring的IoC
    1、耦合、解耦的概念

    耦合: 是指对象和对象之间产生的依赖关系,依赖关系越高,耦合性越高,依赖关系越低,耦合性越低。
    在开发项目时,尽量不要让对象之间的依赖关系太高。
    解耦: 降低对象之间耦合性的过程叫做解耦(解耦只是降低耦合性,但不能彻底消除)
    Class AnimalTest{
        Animal ani = spring容器对象.getBean("animal")
        //Animal ani = new Cat();
    }
    interface Animal{}
    class Cat implements Animal{}
    ------------------------------------------------
    beans.xml
        animal    com.tedu.Cat

    2、Spring IoC概念

    IoC(Inverse Of Control):控制反转,是指将对象的创建交给框架负责
        在spring框架之前,当需要对象,我们负责控制对象的创建(new的形式),以及对象的销毁
        但由于new对象会造成对象之间的依赖关系提升(即耦合度提升)
        因此可以将对象的创建交给spring负责,将创建对象的权利交给框架,这里我们称之为"控制反转"
        

    3、Spring IoC入门

    1)创建Maven的java工程:CGB-SPRING-01
    2)在pom.xml文件中导入junit、spring的依赖包
    3)提供com.tedu.pojo.User类(将User类的实例交给spring框架创建)
    4)在src/main/resources下提供spring的配置文件--beans.xml,并添加如下配置
        <!-- 将User作为bean装配到spring容器中(将User类的实例交给spring容器创建)
            id属性: 定义一个编号, 将来通过这个编号可以获取当前类的实例(id必须是唯一的)
                id值通常是当前类的类名(但首字母小写), 或者当前类父接口的接口名(首字母小写)
            class属性: 指定当前类的全类名(spring框架会通过反射+全类名创建该类的实例) -->
        <bean id="user"  class="com.tedu.pojo.User">
        
    5)提供测试类,测试spring的IoC
        public class SpringTest {
            //获取spring的容器对象
            ClassPathXmlApplicationContext ac = 
                    new ClassPathXmlApplicationContext("beans.xml");
            /* 1、测试spring的IoC */
            @Test
            public void testIoC(){
                //从spring容器中获取User类的实例(对象)
                User user = (User)ac.getBean( "user" ); //根据id获取bean
            }
        }
                

    三、Spring的单实例和多实例

    /*
     * 单例: 默认spring容器中所有的bean对象都是单例的( 即每个类只创建一个对象 )
     *         优点: 无论获取一个bean多少次, 返回都是同一个实例(因为只创建了一个实例)
     *             可以节省内存空间, 减少资源浪费。
     *         缺点: 可能会引发线程安全问题(如果这个唯一对象上有共享数据,并且多个线程会同时
     *             操作这个共享数据)
     *         单例的bean是在beans.xml文件一被读取就会创建实例, 而且会存到bean池中
     *
     * 多例: 如果在bean标签上设置scope="prototype", 当前bean对象就是多例的
     *        <bean id="user" scope="prototype" class="com.tedu.pojo.User">
     *         每次获取当前类的实例, spring容器都会创建该类的新的实例
     *         优点: 不会引发线程安全问题( 因为每个线程持有的实例是不同的 )
     *         缺点: 由于每次获取都会创建新的实例, 会占用服务器的内存空间, 浪费资源
     *         多例的bean是每次获取时才会创建实例, 而且创建的实例不会存到bean池中
     * 
     * 总结: 从使用频次上, 如果一个对象使用的频率特别高, 建议使用单例
     *         反过来说, 如果一个对象使用频率特别低, 建议使用多例。
     */
    @Test
    public void testScope() {
        //获取UserInfo类的实例(多例)
        UserInfo info1 = (UserInfo)ac.getBean( "userInfo" );
        UserInfo info2 = (UserInfo)ac.getBean( "userInfo" );
        System.out.println( info1 == info2 ); //false, 地址不相等, 说明不是同一个对象
        
        //获取User类的实例(单例)
        User u1 = (User)ac.getBean( "user" );
        User u2 = (User)ac.getBean( "user" );
        System.out.println( u1 == u2 ); //true, 因为是同一个对象, 所以地址相等
    }
    

    四、Spring的DI

    /*
     * 测试spring的DI(依赖注入)
     *     依赖注入:在创建对象的同时或者之后,为对象的属性赋值
     *     1)set方法注入:在创建对象之后,框架在底层调用对象的setXxx方法为xxx属性赋值
     *         例如: 调用 setName方法给name属性赋值
     *     2)构造方法注入:底层是在创建对象的同时,通过构造方法给对象的属性赋值
     */
    @Test
    public void testDI() {
        //获取User类的实例
        User user = (User)ac.getBean( "user" );
        System.out.println( user );
    }
    ========================================================
    <!-- 使用set方法为User对象的name、age、info变量赋值
        需要注意的是: name属性指定的值, 在当前类中得有对应的set方法 -->
    <bean id="user"  class="com.tedu.pojo.User">
        <property name="name"  value="韩少云" />
        <property name="age"  value="30" />
        <property name="info"  ref="userInfo"/>
    </bean>
    ========================================================
    <!-- 使用构造方法为User对象的name、age、info属性赋值
        其中name属性的值 要和构造方法上形参的名字保持一致
     -->
    <bean id="user"  class="com.tedu.pojo.User">
        <constructor-arg name="name"  value="马云"/>
        <constructor-arg name="age"  value="38"/>
        <constructor-arg name="info"  ref="userInfo"/>
    </bean>
    ========================================================

    五、Spring的全注解开发
    1、spring全注解开发入门

    1)创建Maven的java工程:CGB-SPRING-02
    2)在pom.xml文件中导入junit、spring的依赖包
    3)提供com.tedu.pojo.User类(将User类的实例交给spring框架创建)
    4)提供 com.tedu.AppConfig 类,作为Java配置类
    ========================================================
    /* @Configuration: 通知spring框架这是一个Java配置类, spring框架通过
     * 这个类中的配置, 生成spring容器对象。AppConfig类 == beans.xml文件
     */
    @Configuration
    public class AppConfig {
        /* @Bean(name="user"): 将当前方法的返回值作为bean装配到spring容器中
         *         其中name指定的值就是bean的id值(即bean的名称), 相当于<bean>标签
         *         如果不添加括号及其中的name属性, bean的id值就是方法名 */
        @Bean(name="user")
        public User getUser() {
            User user = new User();
            user.setName( "赵云" );
            user.setAge( 28 );
            return user;
        }
    }
    ========================================================
    5)提供测试类,测试spring的全注解开发
    public class SpringTest {
        //获取spring的容器对象
        AnnotationConfigApplicationContext ac = 
                new AnnotationConfigApplicationContext( AppConfig.class );
        /* 1、测试spring的全注解开发 */
        @Test
        public void testIoC01() {
            //从spring容器中获取User类的实例
            User u1 = (User)ac.getBean( "user" );
            System.out.println( u1 );
        }
    }
    

    2、通过扫描装配Bean

    1)将上面AppConfig中 @Bean注解及标记的getUser方法 注释或者直接删除
    2)在AppConfig类上添加 @ComponentScan 注解
        /* @Configuration: 通知spring框架这是一个Java配置类, spring框架通过
         * 这个类中的配置, 生成spring容器对象。AppConfig类 == beans.xml文件
         * @ComponentScan: 用于配置以何种策略扫描装配bean, 如果后面什么都不加
         *         默认扫描当前类所在的包(com.tedu)及其子包(com.tedu.*)
         *         如果扫描到包中的类上有@Component注解,就会将这个类作为bean进行装配
         */
        @Configuration
        @ComponentScan
        public class AppConfig {
            /* ... */
        }
    3)在User类上添加 @Component("user") 注解
        @Component("user")
        public class User {
            ...
        }
    4)再执行 SpringTest 类中 testIoC01 方法进行测试
    
    @ComponentScan: 配置以何种方式扫描装配bean, 默认扫描当前类所在的包及其子包
        比如,当前类是 com.tedu.AppConfig, 所在的包就是 com.tedu
        默认扫描的包就是 com.tedu 包以及以 com.tedu 开头的所有子包
    @ComponentScan( basePackages = "com.tedu.dao" )
        basePackages指定扫描哪个包,上面指定了只扫描 com.tedu.dao 包
    @ComponentScan( basePackages = { "com.tedu.dao", "com.tedu.service" } )
        basePackages同时可以指定扫描多个包,将多个包放在一个数组中即可, 
        上面指定了扫描 com.tedu.dao包 和扫描 com.tedu.service包
    

    3、@AutoWired自动装配(依赖注入)

    如果是给一个字符串类型的变量或者数值类型的变量赋值,可以直接通过@Value注解给对象的属性赋值。
    1)修改User类,在User类中添加一个Animal类型的animal属性,并提供对应的get和set方法
    2)重写User类中的toString方法
    3)添加一个com.tedu.pojo.Animal接口,并未Animal接口提供一个实现类--com.tedu.pojo.Dog
    4)通过@AutoWired注解为User对象的animal属性赋值, 赋的值是一个Animal类型的对象
    
    @Component("dog") //将Dog类作为bean装配到spring容器中(spring容器中是包含Dog对象的)
    public class Dog implements Animal
    
    @Autowired
    private Animal animal;
    
    @Autowired注解的作用:
    1)@AutoWired注解是我们使用非常多的注解之一,它可以将定义好的bean对象(比如Dog对象)作为值 赋值给其它对象的属性。这个过程是自动完成的,我们称之为自动装配(依赖注入)
    2)@AutoWired注解默认优先按照(Animal)类型到spring容器中进行查找bean,如果找到一个则直接将这个bean对象作为值赋值给animal属性。如果找不到,则抛出异常!
    3)如果该类型(Animal)的bean在spring容器中有多个,此时还会根据变量名/属性名去匹配,如果变量名/属性名 和 bean的id值相同,就可以自动装配。如果都不相同,也会抛出异常。
    4)如果该类型(Animal)的bean在spring容器中有多个,可以通过@Qualifier显式的为属性指定要注入哪一个名称的bean
    

    4、@Scope指定bean的作用范围

    @Scope("prototype")
    public class User{
        ...
    }
    如果不指定scope属性或者@Scope注解,在spring容器中所有的bean都是单实例的(spring容器为所有的类只创建一个实例。)
    如果指定scope="prototype" 或者 @Scope("prototype"),可以指定当前bean为多实例,即每次通过spring容器获取当前类的实例,都会创建新的bean对象并返回!
    

    5、注解小结:

    @Configuration:通知spring框架当前类是一个Java配置类, 通过其中的配置
        可以获取spring容器对象。( Appconfig相当于beans.xml文件)
        
    @Bean注解:将当前方法的返回值作为bean装配到spring容器中
        bean的名称(id值)默认是方法名,可以在@Bean注解后面指定id值
        这种方式不是我们以后的主流形式,通常是用在将第三方的类作为bean装配到spring容器中时使用!
    
    @Component注解: 将当前类作为bean装配到spring容器中
        前提是这个类所在的包能被spring框架扫描到
        bean的名称(id值)默认是类名(但首字母小写),也可以在@Component注解后面指定bean的名称
        
    @ComponentScan( basePackages = "com.tedu.pojo" ):
        配置以何种方式扫描装配bean,basePackages指定扫描哪个包,上面指定了只扫描 com.tedu.pojo 包
    @ComponentScan( basePackages={"com.tedu.pojo","com.tedu.dao"} ):
        basePackages可以同时指定扫描多个包,将多个包放在一个数组中即可,
        上面指定了扫描 com.tedu.pojo包 和扫描 com.tedu.dao包
    @ComponentScan: 如果不指定扫描哪些包,默认扫描当前类所在的包及其子包
        比如,当前类是 com.tedu.AppConfig,所在的包就是 com.tedu
        默认扫描的包就是 com.tedu 包以及以 com.tedu.* 开头的所有子包

    16 声望8 粉丝

    « 上一篇
    Mybatis
    下一篇 »
    SpringMVC