Bootstrap

Spring SpringMVC SpringBoot 常用注解说明

Spring

注解与xml配置的区别

Spring使用.xml配置来注入或者配置Aop,事务,主要缺点有两个:

  1. 内容都配置在.xml文件中,那么.xml文件将会十分庞大。按需求分开.xml文件,那么.xml文件又会非常多,将导致配置文件的可读性与可维护性变得很低。
  2. 在开发中在.java文件和.xml文件之间不断切换,是一件麻烦的事,同时这种思维上的不连贯也会降低开发的效率。为了解决这两个问题,Spring引入了注解,让注解与Java Bean紧密结合,既大大减少了配置文件的体积,又增加了Java Bean的可读性与内聚性。
不使用注解的案例

定义老虎

	public class Tiger {
   
   		 private String tigerName="Tiger";
   		 public String toString(){
   
      		 return "TigerName:"+tigerName;
    	 }
	}

定义猴子

	public class Monkey {
   
  	    private String monkeyName = "Monkey";
   	    public String toString(){
   
     	   return "MonkeyName:" + monkeyName;
 	   }
	}

定义动物园


public class Zoo {
   
    private Tiger tiger;
    private Monkey monkey;
    public Tiger getTiger() {
   
        return tiger;
    }
    public void setTiger(Tiger tiger) {
   
        this.tiger = tiger;
    }
    public Monkey getMonkey() {
   
        return monkey;
    }
    public void setMonkey(Monkey monkey) {
   
        this.monkey = monkey;
    }
    public String toString(){
   
        return tiger + "\n" + monkey;
    }
}

Spring配置文件

<?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:p="http://www.springframework.org/schema/p"
    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-3.0.xsd
    ">
    
     <bean id="zoo" class="com.spring.Zoo" >
        <property name="tiger" ref="tiger" />
        <property name="monkey" ref="monkey" />
    </bean>
    <bean id="tiger" class="com.spring.Tiger" />
    <bean id="monkey" class="com.spring.Monkey" />

</beans>

测试方法(不使用注解)

public class TestAnnotation {
   
    @Test
    public void test(){
   
        //读取配置文件
        ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
        Zoo zoo=(Zoo) ctx.getBean("zoo");
        System.out.println(zoo.toString());
    }
}
@Autowired

@Autowired自动装配,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。 getter看个人需求,如果私有属性需要对外提供的话,应当予以保留
@Autowired默认按类型匹配的方式,在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。

因此,引入@Autowired注解,先看一下spring配置文件怎么写:

<?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:p="http://www.springframework.org/schema/p"
    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-3.0.xsd
    ">
    //告知spring要使用注解了,spring会自动扫描com.spring路径下的注解
    <context:component-scan base-package="com.spring" />
    
    <bean id="zoo" class="com.spring.Zoo" />
    <bean id="tiger" class="com.spring.Tiger" />
    <bean id="monkey" class="com.spring.Monkey" />
</beans>

原来zoo里面应当注入两个属性tiger、monkey,现在不需要注入了。再看下,Zoo.java也很方便,把getter/setter都可以去掉:

public class Zoo {
   
    @Autowired
    private Tiger tiger;
    @Autowired
    private Monkey monkey;
    public String toString(){
   
        return tiger + "\n" + monkey;
    }
}

这里@Autowired注解的意思就是,当Spring发现@Autowired注解时,将自动在代码上下文中找到和其匹配(默认是类型匹配)的Bean,并自动注入到相应的地方去。
有一个细节性的问题是,假如bean里面有两个property,Zoo.java里面又去掉了属性的getter/setter并使用@Autowired注解标注这两个属性那会怎么样?答案是Spring会按照xml优先的原则去Zoo.java中寻找这两个属性的getter/setter,导致的结果就是初始化bean报错。

假设把xml配置中,下面两行去掉,再运行,会抛出异常:

<bean id="tiger" class="com.spring.Tiger" />
<bean id="monkey" class="com.spring.Monkey" />
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'zoo': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.spring.model.Tiger com.spring.model.Zoo.tiger; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.spring.model.Tiger] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

因为,@Autowired注解要去寻找的是一个Bean,Tiger和Monkey的Bean定义都给去掉了,自然就不是一个Bean了,Spring容器找不到也很好理解。那么,如果属性找不到我不想让Spring容器抛出异常,而就是显示null,可以吗?可以的,其实异常信息里面也给出了提示了,就是将==@Autowired注解的required属性设置为false即可==:

public class Zoo {
   
    @Autowired(required=false)
    private Tiger tiger;
    @Autowired(required=false)
    private Monkey monkey;
    public String toString(){
   
        return tiger + "\n" + monkey;
    }
}

此时,找不到tiger、monkey两个属性,Spring容器不再抛出异常而是认为这两个属性为null。

@Qualifier

如果容器中有一个以上匹配的Bean,则可以通过@Qualifier注解限定Bean的名称,看下面的例子:
定义一个Phone接口:

public interface IPhone{
   
    public String getPhoneName();
}

两个实现类xiaomiPhone和huaweiPhone:

public class xiaomiPhone implements IPhone{
   
    public String getPhoneName(){
   
        return "xiaomi Phone";
    }
}
public class huaweiPhoneimplements IPhone{
   
    public String getPhoneName(){
   
        return "huawei Phone";
    }
}

再写一个PhoneFactory,引用Iphone(这里先不用@Qualifier注解):

public class CarFactory {
   
    @Autowired
    private IPhone phone;
    public String toString(){
   
        return phone.getPhoneName();
    }
}

配置文件:

<?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:p="http://www.springframework.org/schema/p"
    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-3.0.xsd
    ">
    
    <context:component-scan base-package="com.spring" />
    
    <!-- Autowired注解配合Qualifier注解 -->
    <bean id="PhoneFactory" class="com.spring.PhoneFactory" />
    <bean id="xiaomiPhone" class="com.spring.service.impl.xiaomiPhone" />
    <bean id="huaweiPhone" class="com.spring.service.impl.huaweiPhone" />
</beans>

测试方法:

/**
 * Autowired注解配合Qualifier注解
 */
@Test
public void test1(){
   
    //读取配置文件
    ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
    PhoneFactory phoneFactory=(PhoneFactory) ctx.getBean("PhoneFactory");
    System.out.println(phoneFactory.toString());
}

运行一下,不用说,一定是报错的,Phone接口有两个实现类,Spring并不知道应当引用哪个实现类。

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'phoneFactory': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreation
;