zoukankan      html  css  js  c++  java
  • 2、spring注入及自动装配

         

    1. 课程回顾 1-1

    1.1. Spring 概述 1-1

    1.2. Spring IOC 概述 1-2

    1.3. Spring IOC 编程 1-2

    2. Spring Bean依赖 2-2

    2.1.1. 依赖注入基础 2-2

    2.1.2. 依赖注入进阶 2-2

    2.1.3. 依赖值的自动装配 2-5

    3. Spring 注解应用 3-6

    3.1. Spring 注解概述 3-6

    3.2. Spring 注解基本应用 3-6

    3.2.1. 常用注解说明 3-6

    3.2.2. 注解应用案例 3-7

    3.2.3. 配置注解扫描 3-7

    3.2.4. 编写测试类获取bean 3-8

    3.3. Spring 注解应用增强 3-8

    3.3.1. 作用域及生命周期 3-8

    3.3.2. 延迟加载配置 3-8

    3.3.3. 自动装配配置 3-9

    4. 总结 4-9

    4.1. 重点和难点分析 4-9

    4.2. 常见FAQ 4-9

     

      1. 课程回顾

        1.1. Spring 概述

        1. Spring 是什么?(框架,半成品)
        2. Spring 能解决什么问题(面向对象,面向切面,面向服务)
        3. Spring 框架核心?(IOC,AOP,MVC,…)

               个人认为:Spring 最强大是它的资源整合能力。

        1.2. Spring IOC 概述

          1. IOC是什么?(控制反转:由spring构建对象,管理对象依赖)
          2. IOC 应用优势?(解耦,更好的管理对象,使用系统资源)
          3. IOC 的核心?(工厂,配置,依赖注入)
          4. IOC 编程步骤?(类,配置,获取)

        1.3. Spring IOC 编程

        1. Spring Bean对象初始化,作用域,声明周期,延迟加载

                1) Bean类型的编写(修饰符,构造方法)

                2) Bean 的配置(applicationContext.xml)

                3) Bean 的作用域(singleton,prototype)

                4) Bean 的生命周期(生命周期方法的使用)

                5) Bean 的延迟加载(局部lazy-init,全局 default-lazy-init)

        1. Spring Bean依赖(依赖注入,自动装配)

                1) 依赖注入(DI)的定义(通过spring为类中的属性注入值)

                2) 依赖注入的实现(set注入,构造注入)

                3) 依赖注入中的集合值的注入(数组,list,set,map)

                4) 依赖注入中的自动装配(未讲)

        2. Spring Bean依赖

            2.0.1. 依赖注入基础

              重点了解set,构造注入的方式以及单个值如何实现注入。

            2.0.2. 依赖注入进阶

              重点了解集合类型值的注入,例如listhashmap,properties

                案例1

                定义一个相对复杂的对象

                  public class ComplexObject {

                    private String[] names;

                    private List<String> address;

                    private Map<String,Integer> map;

                    private Properties properties;

                    //set,get

                  }

                在配置文件中配置此对象,并为属性注入值

    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans 
    
        default-lazy-init="true"
    
        xmlns="http://www.springframework.org/schema/beans" 
    
        xmlns:p="http://www.springframework.org/schema/p"
    
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    
        xmlns:context="http://www.springframework.org/schema/context"
    
        xmlns:tx="http://www.springframework.org/schema/tx"
    
        xmlns:aop="http://www.springframework.org/schema/aop"
    
        xmlns:mvc="http://www.springframework.org/schema/mvc"
    
        xmlns:util="http://www.springframework.org/schema/util"
    
        xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    
        xsi:schemaLocation="  
    
           http://www.springframework.org/schema/beans   
    
           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd  
    
           http://www.springframework.org/schema/mvc   
    
           http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd   
    
           http://www.springframework.org/schema/tx   
    
           http://www.springframework.org/schema/tx/spring-tx-4.3.xsd   
    
           http://www.springframework.org/schema/aop
    
           http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
    
           http://www.springframework.org/schema/util
    
           http://www.springframework.org/schema/util/spring-util-4.3.xsd
    
           http://www.springframework.org/schema/data/jpa
    
           http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
    
           http://www.springframework.org/schema/context
    
           http://www.springframework.org/schema/context/spring-context-4.3.xsd"> 
    
              
    
          <bean id="cObj" class="beans.ComplexObject">
    
             <!-- 为String[]数组属性注入值 -->
    
             <property name="names">
    
                 <list>
    
                    <!-- #{}为spring中的一个表达式 -->
    
                    <value>name-1</value>
    
                    <value>name-2</value>
    
                 </list>
    
             </property>
    
             <!-- 为list<String>集合注入值 -->
    
             <property name="address">
    
                 <list>
    
                   <value>北京</value>
    
                   <value>深圳</value>
    
                   <value>上海</value>
    
                 </list>
    
             </property>
    
             <!-- 为map属性注入值 -->
    
             <property name="map">
    
                <map>
    
                   <entry key="k1" value="200"/>
    
                   <entry key="k2" value="300"/>
    
                </map>
    
             </property>
    
             <!-- 为properties属性注入值 -->
    
             <property name="properties">
    
                <props>
    
                  <prop key="pk1">pv1</prop>
    
                  <prop key="pk2">pv2</prop>
    
                </props>
    
             </property>      
    
          </bean>
    
    </beans>
    
     

          案例2spring配置文件中引入properties文件中的数据

            step1:类路径的根目录定义properties文件cfg.properties,其内容如下:

                driver=com.mysql.jdbc.Driver

                url=jdbc:mysql:///test

                username=root

                password=root

          step2:spring配置文件中引入此配置文件(借助util标签) 

            <util:properties   id="cfg"   location="classpath:cfg.properties"/>

          step3:在Bean对象中引入配置文件中的值 

                   <bean id="dataSource" class="beans.DataSource">

                          <property name="driver" value="#{cfg.driver}"/>

                          <property name="url"  value="#{cfg.url}"/>

                          <property name="username" value="#{cfg.username}"/>

                          <property name="password" value="#{cfg.password}"/>

                   </bean>

              其中#{}spring中一个表达式,通过这个表达式可以获取properties文件中的值

              例如#{cfg.driver}为获取idcfg对应的对象中keydriver的值。

        2.0.3. 依赖值的自动装配 

          Spring中为bean对象中的属性提供了自动装配功能,此功能的开启需要借助bean标签中的autowire属性进行指定,此属性的值默认有如下几个:

     

    NO 

    自动配置(默认)

     

    ByName

    按名字自动装配(重点掌握)

     

    ByType

    按类型自动状态(重点掌握),但有多个类型时会出错

     

    Constructor

    byType类似,不同之处在于它应用于构造器参数。

           例如:

            定义并配置DataSource对象

              public class DataSource {

              }

             <bean id="dataSource" class="beans.DataSource"/>

              定义并配置JdbcTemplate对象

              public class JdbcTemplate {

                private DataSource dataSource;

                public JdbcTemplate() {}

                public JdbcTemplate(DataSource dataSource) {

                   this.dataSource=dataSource;

                  }

              public void setDataSource(DataSource dataSource) {

                this.dataSource = dataSource;

                }

       <bean id="jdbcTemplate" class="beans.JdbcTemplate" autowire="constructor"> </bean>

          自动装配应用总结

            v byName 按属性对应的set方法名从容器中查找名字相同的bean,然后进行注入。假如出现了名字相同,但类型不同的Bean对象时,会注入失败

            v byType 先从容器中查找属性类型相匹配的值然后找按类中对应的set方法(看参数类型)最后通过set方法为对象的属性注入值。假如容器中出现多个类型相同的对象,就会注入失败。

            v constructor 先从容器中查找属性类型相匹配的值然后找类中对应的构造方法(看参数类型)最后通过构造方法为对象的属性注入值。假如容器中出现多个类型相同的对象,此时再比对参数名字,假如有同名的则直接注入,没有同名的就会注入失败。

        3. Spring 注解应用

          3.1. Spring 注解概述

              Spring中提供了两种方式对Bean进行描述,一种是基于xml方式,一种是基于注解方式。基于注解方式主要是依托于注解对bean以及bean中的属性进行描述

              然后spring底层通过反射获取bean上定义的这些注解,通过注解描述初始化对象,管理对象的作用域以及对象与对象之间的依赖。

          3.2. Spring 注解基本应用 

            3.2.1. 常用注解说明

              组件应用注解

     

    注解名

    说明

     

    @Component

    通用注解

     

    @Repository

    持久层组件应用注解

     

    @Service

    业务层组件应用注解

     

    @Controller

    控制层组件应用注解

        3.2.2. 注解应用案例

           数据层对象

            @Repository 

          业务层对象

            @Service 

          控制层对象

            @Controller

       3.2.3. 配置注解扫描

           Spring中通过指定一个包路径,由系统自动扫描该包及其子包所有组件类,当发现组件类定义前有特定的注解标记时,就将该组件纳入到Spring容器。

          例如:用组件扫描,首先需要在XML配置中指定扫描父级package路径,例如

             <context:component-scan base-package=”com.company.spring/>”

           在这个配置中,容器会自动扫描org.example包及其子包下所有组件,并实例化bean对象。

          3.2.4. 编写测试类获取bean

        3.3. Spring 注解应用增强

          3.3.1. 作用域及生命周期

    @Scope("singleton")
    @Repository
    public class SysUserDao {
          /**@PostConstruct注解修饰方法在对象初始化时执行*/
          @PostConstruct
          public void init(){
            System.out.println("init");  
          }
          public void insertObject(){
              System.out.println("insertObject");
          }
          /**@PreDestroy对象销毁时执行*/
          @PreDestroy
          public void destory(){
              System.out.println("destory");
          }
    }

    3.3.2. 延迟加载配置

    @Lazy(false)
    @Service
    public class SysUserService {
    }

     

        3.3.3. 自动装配配置

          注解方式的自动装配一般会借助@Autowired@Resource实现,具体过程参考   

          注解自动装配使用说明:

            应用位置

            1@Autowired/@Qualifier 一般用于修饰属性和构造方法

            2@Resource 一般用于修饰属性和set方法

          注入规则:

            1@Autowired 修饰属性,构造方法,set方法时默认按照属性类型或参数类型进行值的注入。假如容器中有多个类型相同的Bean,此时还会按名字进行匹配,没有相匹配的则注入失败。假如希望按名字进行匹配需要再此基础加上@Qualifier注解。

            2@Resource 修饰属性,set方法时默认按属性名或set方法名进行匹配,假如Resource指定了名称则按指定名称进行匹配,假如没有找到相匹配的名称,则按类型进行值的注入。

      1. Spring 注解工厂应用剖析

         1.1. Bean工厂是用于做什么的?

           所有的工厂都是用于创建对象的,对象创建一般会基于某中策略对对象进行存储。

          例如Spring 中的Bean工厂:ApplicationContext

            1) ClassPathXmlApplicationContext

            2) AnnotationApplicationContext

            3) …….

      1.2. Bean工厂的实现的基本原理?

          Spring 中所有的Bean假如需要由Spring管理,此时需要以xml描述的方式或注解的描述方式告诉spring容器。Spring底层内置了对xml的解析,通过反射获取注解描述,然后基于这些描述通过反射构建对象。

      1.3. Bean工厂理解的拔高?

          手写基于注解方式的Spring Bean工厂

            1) 包的扫描(将包转换为类所在的路径,然后进行文件的查找)

            2) 构建类全名(包名+类名,例如java.util.Date

            3) 基于反射构建类的对象(获取Class对象,构建构造方法对象,构建类的实例对象)

            4) 存储类的对象(key是谁)

            5) 需要时从工厂中获取bean对象即可

      1.4. Bean 工厂手写应用实践

           1.4.1. 注解定义实现

            定义一个用于修饰bean,描述bean的注解。

              @Retention(RetentionPolicy.RUNTIME)

              @Target(ElementType.TYPE)

              public @interface Component {     

                String value() default "";

              }

          定义一个用于描述配置的注解

             @Retention(RetentionPolicy.RUNTIME)

            @Target(ElementType.TYPE)

            public @interface ComponentScan {

                String value() default "";

            }

        1.4.2. 定义Bean组件

          定义一个IdGenerator类,然后使用@Component注解修饰

           @Component

          public class IdGenerator {}

        1.4.3. 定义Bean工厂

          这个Bean工厂要实现的功能是基于配置类上的@ComponentScan注解,对注解中定义包进行类的扫描,然后构建类的对象,再将对象存储到map集合,需要时从map获取。其代码如下:

    public class AnnotationAppContext{
        private Map<String,Object> beanMap=
        new HashMap<String,Object>();
        public AnnotationAppContext(Class<?> c)throws Exception{
            //1.获取class(例如AppConfig)上的@ComponentScan注解
            ComponentScan cs=c.getAnnotation(ComponentScan.class);
            //2.获取注解中定义的包名
            String pkg=cs.value();
            //替换包名中的“.”,改成目录结构
            String dir=pkg.replaceAll("\.", "/");
            //3.基于包获取包对应的类路径
            URL url=
            getClass().getClassLoader()
            .getResource(dir);
            System.out.println("url="+url);
            //4.获取类路径下所有的class文件(例如IdGenerator)
            File pkgDir=new File(url.getPath());
            //4.1获取目录下所有class文件
            File[] fs=pkgDir.listFiles();//class
            //4.2遍历所有文件,构建类全名
            for(File f:fs){
                String fname=
                f.getName().substring(0,f.getName().lastIndexOf("."));
                String clsName=pkg+"."+fname;
                Class<?> cls=Class.forName(clsName);
                //5.基于class文件上注解(@Component)描述构建类对象
                if(!cls.isAnnotationPresent(Component.class))
                continue;
                Object obj=newInstance(cls);
                //6.将类对象存储到map集合
                //6.1获取key的值
                Component cp=cls.getAnnotation(Component.class);
                String key=cp.value();
                if("".equals(key)){
                    key=String.valueOf(
                    fname.charAt(0)).toLowerCase()+
                    fname.substring(1);
                }
                //6.2存储到map
                beanMap.put(key, obj);
            }
        }
        private Object newInstance(Class<?> cls)
        throws Exception{
            Constructor<?> c=
            cls.getDeclaredConstructor();
            c.setAccessible(true);
            return c.newInstance();
        }
        public Object getBean(String beanName){
            return beanMap.get(beanName);
        }
        @SuppressWarnings("unchecked")
        public <T>T getBean(String beanName,
                Class<T> cls){
            return (T) beanMap.get(beanName);
        }
        public static void main(String[] args)
        throws Exception{
            AnnotationAppContext ctx=
            new AnnotationAppContext(AppConfig.class);
            
            IdGenerator obj1=(IdGenerator)
            ctx.getBean("idGenerator");
            IdGenerator obj2=
            ctx.getBean("idGenerator",IdGenerator.class);
            
            System.out.println(obj1);
            System.out.println(obj2==obj1);
        }
    }

    2. 总结

    2.1. 重点和难点分析

    1. Spring 注解的强化理解
    2. Spring 注解方式实现自动装配
    3. Spring Bean工厂手写方式的实现。

    2.2. 常见FAQ

    1. URL是什么
    2. URL的值什么情况下为空
    3. 注解是什么,如何自己定义
    4. 工厂应用中泛型方法如何实现

    2.3. 作业

    1. 总结spring注解应用
    2. 尝试手写spring bean 工厂
  • 相关阅读:
    [洛谷P4774] [NOI2018]屠龙勇士
    [洛谷P3338] [ZJOI2014]力
    [洛谷P1707] 刷题比赛
    svn查看指定版本提交信息的命令
    ajax无刷新上传文件
    给docker里的php安装gd扩展
    PHP基于openssl实现的非对称加密操作
    php获取文件扩展名
    javascript格式化日期
    javascript获取url参数
  • 原文地址:https://www.cnblogs.com/xiangyuqi/p/8653875.html
Copyright © 2011-2022 走看看