Spring SpringMVC SpringBoot 常用注解说明
Spring
注解与xml配置的区别
Spring使用.xml配置来注入或者配置Aop,事务,主要缺点有两个:
- 内容都配置在.xml文件中,那么.xml文件将会十分庞大。按需求分开.xml文件,那么.xml文件又会非常多,将导致配置文件的可读性与可维护性变得很低。
- 在开发中在.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