Spring源码学习--@Autowired注解和启动⾃动扫描的三种⽅式
引⽤⽂章地址:
前⾔:
@Autowired注解代码定义
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD,
ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
resource和autowired注解的区别
从上述定义中,我们可以得出@Autowired注解只有⼀个属性即required属性,此属性的默认值为true,即默认情况下它要求依赖对象必须存在,如果不存在会出现空指针等错误;如果允许为null,可以设置它required属性为false.其中@Autowired注解和标注的变量的类的set和get⽅法⽆关,⾃动装配的实现并不是依赖set⽅法的⽅式实现的.在xml中利⽤
<property name="" value="" />
这种⽅式是依赖对应类的set⽅法的⽅式实现的 @Autowired注解使⽤之前⾸先确定判断⼀下此处能够使⽤@Autowired注解.
⼀、 @Autowired注解使⽤场景介绍
(1)构造函数
(2)成员变量
(3)Setter⽅法
(4)普通⽅法
⼆、 @Autowired注解所涉及的原理部分
其实在启动spring IoC时,容器⾃动装载了⼀个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、
@Resource或@Inject时,就会在IoC容器⾃动查需要的bean,并装配给该对象的属性
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
注意事项:
在使⽤@Autowired时,⾸先在容器中查询对应类型的bean,
如果查询结果刚好为⼀个,就将该bean装配给@Autowired指定的数据
如果查询的结果不⽌⼀个,那么@Autowired会根据名称来查。
如果查询的结果为空,那么会抛出异常。解决⽅法时,使⽤required=false
上述过程说明了@Autowired注解默认是按照类型装配注⼊的,默认情况下它要求依赖对象必须存在如果允许为null,可以设置它required属性为false,如果想按照名称来转配注⼊,则需要结合@Qualifier⼀起使⽤;
三、处理使⽤@Autowired注解出现⾃动装配的歧义性问题
使⽤@Autowired注解的过程中,如果出现NoUniqueBeanDefinitionException异常,⼤多是因为⾃动装配或者其他⽅式装配所导致的歧义性.即⼀个接⼝存在两个以上的实现类.即在⾃动装配的时候,可能出现因重名问题导致的NoUniqueBeanDefinitionException异常.
@Autowired是按类型进⾏装配的,那么我⼀个接⼝UserInterface,有多个实现类
AImpl(@service(name="userInterface1")),BImpl(@service(name="userInterface2")
等等这些实现类都加⼊了Spring容器,当在⼀个类中使⽤如下语句:
@Autowired
private IUserInterface userInterface;
在下⾯列举⼀下了⼀下,上述问题以及类似的装配歧义性解决问题⽅法.
⽅法⼀
⾸先加上注解@Qualifier来区分不同的实例.通过在实现接⼝的类上通过value属性去命名不同的名称,
对于@Repository、@Service 和
@Controller 和 @Component四个注解都有类似value属性可以设置,例如:
@Service(value="userServiceImpl")
public class UserServiceImpl implements IUserService{
}
@Autowired
@Qualifier("userServiceImpl")
private IUserService userServiceImpl;
⽅法⼆
因为⼀个借⼝存在两个以上的实现类,也可以通过标识⾸选哪个bean,来解决歧义性问题.例如:
@Component
@Primary
public class UserServiceImpl implements IUserService{
}
此时,如果引⽤到了IUserService接⼝的实现类注⼊,则⾸先注⼊@Promary注解标注的类,但是此时有⼀个问题,在同⼀个接⼝的实现类中,你只能使⽤⼀次@Primary,如果对于AImpl和BImpl都使⽤了@primary,则还是会发⽣装配的歧义性.此时,建议使⽤(1)的⽅式来解决歧义性问题.
<4>⽅法三
最后⼀种⽅式,可以使⽤⾃定义的限定符注解,但是此种情况很少出现,再次就不做介绍,可⾃⾏百度.
四、 Spring通过哪些特性实现⾃动装配的?
Spring从两个⾓度来实现⾃动化装配:
(1)组件扫描(component scanning):Spring会⾃动发现应⽤上下⽂中所创建的bean.
(2)⾃动装配(autowiring):Spring⾃动满⾜bean之间的依赖.
组件扫描和⾃动装配组合在⼀起就能发挥出强⼤的威⼒,它们能够将你的显⽰配置降低到最少.
五、@Autowired和@Resource之间的区别
在本⽂只列举出@Autowired和@Resource之间常见的表⾯区别,⾄于区别的原因需要查看Spring官⽅⽂档中的@Autowired注解实现⽅式和Java中@Resource注解实现⽅式.
(1)、@Autowired默认是按照类型装配注⼊的,默认情况下它要求依赖对象必须存在如果允许为null,可以设置它required属性为false,如果想按照名称来转配注⼊,则需要结合@Qualifier⼀起使⽤;
(2)、@Resource默认是按照名称来装配注⼊的,只有当不到与名称匹配的bean才会按照类型来装配注⼊;
(3)、@Resource注解是由J2EE提供,⽽@Autowired是由spring提供,故减少系统对spring的依赖建议使⽤@Resource的⽅式;
(4)、@Resource和@Autowired都可以书写标注在字段或者该字段的setter⽅法之上
(5)、@Resource默认按照名称装配,当不到与名称匹配的bean才会按照类型装配,可以通过name属性指定,如果没有指定name属
性,当注解标注在字段上,即默认取字段的名称作为bean名称寻依赖对象,当注解标注在属性的setter⽅法上,即默认取属性名作为bean
名称寻 依赖对象.注意:如果没有指定name属性,并且按照默认的名称仍然不到依赖的对象时候,会回退到按照类型装配,但⼀旦指定
了name属性,就只能按照名称装配了.
六、Spring是如何启动⾃动扫描的
在这⾥列举出三种启动⾃动扫描的⽅式.
⽅式⼀:此种情况下,针对⽐较特殊的情形,即项⽬中运⽤了SpringBoot,则可以利⽤@SpringBootApplication注解的⽅式启动⾃动扫描功能.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
⽅式⼆:通过XML配置⽅式,启动⾃动扫描功能.XML配置⽅式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xmlns:context="/schema/context"
xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd www.sprin
<context:component-scan base-package="com.tianmaying" />
</beans>
标签将会开启Spring Beans的⾃动扫描,并可设置base-package属性,表⽰Spring将会扫描该⽬录以及⼦⽬录下所有被@Component标
注修饰的类,对它们进⾏装配。
⽅式三:通过Java配置⽅式,启动⾃动扫描功能.
import t.annotation.ComponentScan;
import t.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "fig")
public class BlogSystemConfig {
/**
* 在这⾥实现java⽅式的配置,
*/
}
在这⾥给出⼀个具体的实例:
import org.apachemons.dbcp.BasicDataSource;
import t.annotation.Bean;
import t.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "fig")
public class DataSourceConfig {
@Bean(name="dataSource")//java配置⽅式,配置数据源(dataSource)
public BasicDataSource dataSource(){
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://127.0.0.1:5432/center_db?useUnicode=true&characterEncoding=UTF-8");
dataSource.setUsername("postgres");
dataSource.setPassword("123456");
dataSource.setInitialSize(5);
dataSource.setMaxActive(10);
return dataSource;
}
}
关于@Configuration和@ComponentScan两个注解:
(1)@Configuration表⽰这个Java⽂件是⼀个配置⽂件,这类Java代码的作⽤在于配置,要和普通的Java代码区分开发,因此⼀般我们需要将其放在⼀个专门的包中,在代码例⼦中是fig。
(2)@ComponentScan表⽰开启Spring Beans扫描,类似于XML配置,这⾥也可以可以设置basePackages属性。
如果@ComponentScan注解没有显⽰去给其他的属性赋值的话,⽐如此处给basePackages赋值了,如果没有的话,@ComponentScan注解会扫描与配置类相同的包.
注意:
关于@Repository、@Service 和 @Controller 和 @Component四个注解的使⽤情形
在持久层、业务层和控制层分别采⽤ @Repository、@Service 和 @Controller 对分层中的类进⾏注释,
⽽⽤ @Component 对那些⽐较中⽴的类进⾏注释.这⾥就是说把这个类交给Spring管理,重新起个名字叫userManager,由于不好说这个类属于哪个层⾯,就⽤
@Component.
七、Spring存在⼏种装配⽅式?
⽬前,在Spring中,⼀共提供三种装配⽅式:
(1)基于标注的⾃动装配
(2)基于XML配置的显式装配
(3)基于Java配置的显式装配
在实际项⽬中,⼀般是上述三种装备⽅式都可能存在,不过基于标注的⾃动装配⽅式是在项⽬中最常⽤的.通过给Java类增加相应的标注,就能够启⽤Spring隐式的Bean发现机制,并⾃动完成装配过程.我们在开发中应该尽可能使⽤⾃动装配,⾜以应付开发中的绝⼤多数情况.在某些情况下,基于XML配置和基于Java配置的显式装配会有⽤武之地,⽐如实例化⼀个第三⽅库中的Bean.这种情况下,Java配置和XML配置我们优先使⽤Java配置,因为这是⼀种类型安全的⽅式,能够在编译时就尽早发现错误.
关于上述所说的类型安全可以这样理解:
如果使⽤字符串的形式,在xml中类名或其他硬编码⽅式提供的信息,在开发时是发现不了的,会在运⾏时抛出异常。⽽使⽤Java配置形式,类名或其他硬编码配置信息写错的话,编译时就会提⽰错误,⽐如Eclipse中就会提⽰不到类的错误信息,这就避免了这种情况下的运⾏时异常,因此是更加安全的.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论