zoukankan      html  css  js  c++  java
  • Spring 使用介绍(八)—— 零配置(一)

    一、概述

    所谓零配置,并不是说一点配置都没有了,而是配置很少而已。通过约定来减少需要配置的数量,提高开发效率。

    零配置实现主要有以下两种方式:

    • 惯例优先原则:也称为约定大于配置(convention over configuration),即通过约定代码结构或命名规范来减少配置数量,但不会减少配置文件。
    • 基于注解的规约配置:通过在指定类上指定注解,约定其含义来减少配置数量,从而提高开发效率;如事务注解@Transaction是基于注解的规约,在指定的类或方法上使用该注解就表示其需要事务。

    Spring基于注解的规约配置有三个层级:

    • Bean依赖注入:通过注解方式替代基于XML配置中的依赖注入,如使用@Autowired注解来完成依赖注入。
    • Bean定义:通过注解方式进行Bean配置元数据定义,从而完全将Bean配置元数据从配置文件中移除。
    • Java类替换配置文件:使用Java类来定义所有的Spring配置,完全消除XML配置文件

    二、Bean依赖注入

    1、开启注解支持

    <?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        
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.2.xsd">  
    
        <context:annotation-config />  
    
    </beans>  

    2、@Autowired

    @Autowired根据类型自动注入,可作用于字段、构造器、方法,提供required设置注入是否必须,默认为必须

    public @interface Autowired {
        boolean required() default true;
    }

    示例如下:

    实体类

    public class TestBean {
        private String message1;
        
        // for: 字段注入
        @Autowired
        private String message2;
        
        // for: 静态字段不能注入
        @Autowired
        private static String message3;
    
        private String message4;
        
        // for: 泛型注入
        @Autowired
        private List<String> messages;
        
        // for: 泛型注入(指定具体类型)
        @Autowired
        private ArrayList<String> messages2;
        
        // for: 构造器注入
        @Autowired
        private TestBean(String msg) {
            this.message1 = msg;
        }
        
        public String getMessage1() {
            return message1;
        }
    
        public String getMessage2() {
            return message2;
        }
        
        public String getMessage3() {
            return message3;
        }
    
        public String getMessage4() {
            return message4;
        }
    
        // for: 方法注入
        @Autowired
        public void setMessage4(String message4) {
            this.message4 = message4;
        }
    
        public List<String> getMessages() {
            return messages;
        }
        
        public List<String> getMessages2() {
            return messages2;
        }
    }

    XML配置

    <bean class="java.util.ArrayList">
        <constructor-arg index="0">  
            <list value-type="java.lang.String">  
             <value>matt</value>  
             <value>pretty</value>  
         </list> 
        </constructor-arg>
    </bean>
    
    <bean id="str" class="java.lang.String">
        <constructor-arg index="0" value="kevin"/>  
    </bean>
    
    <bean class="cn.matt.noconfig.TestBean"></bean>

    测试

    @org.junit.Test
    public void testAutowired() {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        TestBean testBean = context.getBean(TestBean.class);
        System.out.println("构造器注入:" + testBean.getMessage1());
        System.out.println("字段注入:" + testBean.getMessage2());
        System.out.println("静态字段不能注入:" + testBean.getMessage3());
        System.out.println("方法注入:" + testBean.getMessage4());
        System.out.println("泛型注入:" + testBean.getMessages());
        System.out.println("泛型注入(指定具体类型):" + testBean.getMessages2());
    }
    /*输出:
    构造器注入:kevin
    字段注入:kevin
    静态字段不能注入:null
    方法注入:kevin
    泛型注入:[kevin]
    泛型注入(指定具体类型):[matt, pretty]
    */

    注意,@Autowired不支持静态字段注入;对于泛型的注入,须明确指定泛型的具体类型,详细如下:

    • 数组类型、集合(Set、Collection、List)接口类型:将根据泛型获取匹配的所有候选者并注入到数组或集合中,如“List<HelloApi> list”将选择所有的HelloApi类型Bean并注入到list中,而对于集合的具体类型将只选择一个候选者,“如 ArrayList<HelloApi> list”将选择一个类型为ArrayList的Bean注入,而不是选择所有的HelloApi类型Bean进行注入;
    • 字典(Map)接口类型:同样根据泛型信息注入,键必须为String类型的Bean名字,值根据泛型信息获取,如“Map<String, HelloApi> map” 将选择所有的HelloApi类型Bean并注入到map中,而对于具体字典类型如“HashMap<String, HelloApi> map”将只选择类型为HashMap的Bean注入,而不是选择所有的HelloApi类型Bean进行注入。

    2、@Value

    @Value注解用于注入SpEL表达式,可放置在字段、@Autowired注解的方法的参数上

    示例如下:

    实体类

    public class TestBean2 {
        
        @Value("#{str}")
        private String message1;
        
        private String message2;
    
        public String getMessage1() {
            return this.message1;
        }
    
        public String getMessage2() {
            return message2;
        }
    
        @Autowired
        public void setMessage2(@Value("#{str}#{str}") String message2) {
            this.message2 = message2;
        }
    }

    XML配置:

    <bean id="str" class="java.lang.String">
        <constructor-arg index="0" value="kevin"/>  
    </bean>
    
    <bean class="cn.matt.noconfig.TestBean2"></bean>

    测试:

    @org.junit.Test
    public void testValue() {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        TestBean2 testBean = context.getBean(TestBean2.class);
        Assert.assertTrue(StringUtils.equals("kevin", testBean.getMessage1()));
        Assert.assertTrue(StringUtils.equals("kevinkevin", testBean.getMessage2()));
    }

    3、@Qualifier

    @Qualifier注解作为修饰符,与@Autowired一起使用,解决类型有多个实例时无法指定某一实例的问题

    示例如下:

    接口及其两个实现类

    public interface Hello {
        void saySomething();
    }
    //@Qualifier("abc")
    @Component("abc")
    public class HelloImpl1 implements Hello {
        @Override
        public void saySomething() {
            System.out.println("HelloImpl1");
        }
    }
    @Component
    public class HelloImpl2 implements Hello {
        @Override
        public void saySomething() {
            System.out.println("HelloImpl2");
        }
    }

    XML配置

    <context:component-scan base-package="cn.matt.noconfig"/>  

    测试

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:spring-context.xml")
    public class BaseSpringTest {
     
    }
    public class SpringTest extends BaseSpringTest {
        @Qualifier("abc")
        @Autowired
        private Hello hello;
        
        @Test
        public void testHello() {
            hello.saySomething();
        }
    }

    说明:

    • @Qualifier可作用于类,用于指定修饰名
    • @Qualifier与@Autowired一起使用指定某一实例时,value可为修饰名(通过@Qualifier指定),也可为bean名(通过@componet指定)
    • 相对于bean名,@Qualifier指定的修饰名可重复,多个类可共用同一修饰名,较灵活,详细可参考 @Qualifier注解

    4、@Resource

    @Resource注解也是自动装配,默认根据类型装配,如果指定name属性将根据名字装配,只能作用于字段和方法

    @Resource(name = "标识符")  
    字段或setter方法  

    5、@PostConstruct与@PreDestroy  

    @PostConstruct与@PreDestroy用于指定初始化和销毁方法,与<bean>标签的init-method和destroy-method属性指定相同

    @PostConstruct  
    public void init() {  
        System.out.println("==========init");  
    }  
    @PreDestroy  
    public void destroy() {  
        System.out.println("==========destroy");  
    }  

    参考:

    第十二章 零配置 之 12.1 概述 ——跟我学spring3

    第十二章 零配置 之 12.2 注解实现Bean依赖注入 ——跟我学spring3

    Spring注解注入bean

    @Qualifier注解

  • 相关阅读:
    神经网络的数学推导
    矩阵乘法的梯度计算
    深入理解设计矩阵(Design Matrix)
    拉格朗日乘子
    PRML中文版(马春鹏)勘误表
    增强学习笔记 第三章 马尔科夫决策过程
    贝叶斯统计推断的阅读笔记
    Kalman Filter的数学推导
    线性代数随笔(二):矩阵和向量乘法
    线性代数随笔(一):线性变换,特征分解,二次型
  • 原文地址:https://www.cnblogs.com/MattCheng/p/9014958.html
Copyright © 2011-2022 走看看