@Autowired注解位置、@Autowired与@Resource的区别与注入流程

文章目录

    • @[toc]
  • 常用注解
    • 注释位置(@Autowired放置在构造器上与放在属性上的区别)
      • 对成员变量注释
      • 对构造函数注释
      • 对成员方法注释
      • @Autowired和构造方法执行的顺序
    • @Autowired与@Resource
      • 注入方式(注意)
        • 基于Setter的依赖注入
        • 基于构造函数的依赖注入
          • 基于setter的依赖注入缺点
      • @Autowired
        • 注入流程
      • @Resource
        • 注入流程
      • @Configuration与@Bean
  • spring Bean单例下的并发问题

常用注解

注释位置(@Autowired放置在构造器上与放在属性上的区别)

@Autowired 可以对成员变量、方法以及构造函数进行注释

对成员变量注释

相当于在配置文件中配置bean,并且使用setter注入

对构造函数注释

就相当于是使用构造函数进行依赖注入

对成员方法注释

如果方法中有实体参数,会对方法里面的参数进行装配,并调用一次该方法

@Component
public class User {
     
}
@Component
public class MyTest {
    @Autowired
    public void myAutowired1(){
        System.out.println("运行了myAutoWired1");
    }
    
    @Autowired
    public void myAutowired2(User user){
        System.out.println("运行了myAutoWired2,user="+user);
    }
}
运行了myAutowired1
运行了myAutoWired2,user=com.chieng.boot.demo.User@4ce1d99f

@Autowired和构造方法执行的顺序

Java变量的初始化顺序为:静态变量或静态语句块–>实例变量或初始化语句块–>构造方法

类加载顺序规定先加载构造方法,再加载普通方法,当构造器中使用到属性时,会发现属性还没有被实例化,则会报错,因此,当构造方法中用到了属性时,应该将注解加在构造器上;

这段代码会报NPE,
    @Autowired
    private User user;
    private String school;

//因为会先执行构造函数,再执行上面的依赖注入,故NPE
    public UserAccountServiceImpl(){
        this.school = user.getSchool();
    }
当构造方法中用到了属性时,应该将注解加在构造器上,如下

    private User user;
    private String school;

    @Autowired
    public UserAccountServiceImpl(User user){
        this.user = user;
        this.school = user.getSchool();
    }

@Autowired与@Resource

https://www.jianshu.com/p/e44f8c6aaa27
https://blog.csdn.net/balsamspear/article/details/87936936


注入方式(注意)

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-dependencies

https://mp.weixin.qq.com/s/34-DdoNcpMUlZiin6Js0Xg

spring官方依赖注入注入有2种:基于构造函数的依赖注入、基于Setter的依赖注入;

基于Setter的依赖注入

通过反射调用无参构造方法进行bean的实例化,然后调用对象的setter方法完成赋值

将注解 放在 函数(不一定是setter函数)上;

public class UserServiceImpl implents UserService{
     private UserDao userDao;
     
     @Autowire
     public setUserDao(UserDao userDao){
         this.userDao = userDao;
     }
 }

基于字段的依赖注入

也算是基于settter注入,也是调用setter方法注入
使用最广,但是并不被spring官方推荐;

public class UserServiceImpl implents UserService{
     @Autowire
     private UserDao userDao;
 }

基于构造函数的依赖注入

指的是有参构造器,将注解放在有参构造器上 即可;

public class UserServiceImpl implents UserService{
    private UserDao userDao;
    
    @Autowire
    public UserServiceImpl(UserDao userDao){
        this.userDao = userDao;
    }
}
基于setter的依赖注入缺点

@Autowired

注入流程

@Autowired只有一个属性required,默认值为true,为true时,找不到就抛异常,为false时,找不到就赋值为null

@Autowired按类型查找,如果该类型的bean不唯一,则将字段名作为beanid注入,如果还是匹配不到,则抛出异常;
可通过组合注解解决@Autowired()@Qualifier("baseDao")
例子

两个同类型的bean不能注入

public class ServiceA {
     
    @Autowired
    private  ServiceB serviceB;
    public String test(){
     
       return serviceB.tb();
    }
}
public class ServiceBImplOne implements ServiceB{
     
    @Override
    public String tb() {
     
        return "ServiceBImplOne";
    }
}
public class ServiceBImplTwo implements ServiceB{
     
    @Override
    public String tb() {
     
        return "ServiceBImplTwo";
    }
}
    <bean id="sa" class="example.autowired.auto.ServiceA"/>
    <bean id="s1" class="example.autowired.auto.ServiceBImplOne"/>
    <bean id="s2" class="example.autowired.auto.ServiceBImplTwo"/>

但是注意下面这个,是可以成功注入的;

public class ServiceA {
     
//先根据类型注入,但是此时有2个类型相同的,故根据filename注入,ServiceB s1,s1=ServiceBImplOne的beanid,故注入成功
    @Autowired
    private  ServiceB s1;
    public String test(){
     
       return s1.tb();
    }
}
public class ServiceBImplOne implements ServiceB{
     
    @Override
    public String tb() {
     
        return "ServiceBImplOne";
    }
}
public class ServiceBImplTwo implements ServiceB{
     
    @Override
    public String tb() {
     
        return "ServiceBImplTwo";
    }
}
   <bean id="sa" class="example.autowired.auto.ServiceA"/>
    <bean id="s1" class="example.autowired.auto.ServiceBImplOne"/>
    <bean id="s2" class="example.autowired.auto.ServiceBImplTwo"/>

@Resource

注入流程

@Resource有两个常用属性name、type,所以分4种情况

同时指定name和type:则从Spring上下文中找到唯一匹配的bean进行装配
指定name:通过name找到唯一的bean,找不到抛出异常
指定type:通过tpye找到唯一的bean,如果不唯一,则抛出异常:NoUniqueBeanDefinitionException
都不指定:通过字段名作为key去查找,找到则赋值;找不到则再通过字段类型去查找,如果不唯一,则抛出异常:NoUniqueBeanDefinitionException

@Configuration与@Bean

spring Bean单例下的并发问题

https://blog.csdn.net/riemann_/article/details/97698560

spring bean默认单例,是线程不安全的,但是如果不涉及到修改数据则是安全的;
例如以下代码,单例情况下,线程不安全,因为涉及到对成员num的修改;

@Controller
public class ScopeTestController {

    private int num = 0;

    @RequestMapping("/testScope")
    public void testScope() {
        System.out.println(++num);
    }

    @RequestMapping("/testScope2")
    public void testScope2() {
        System.out.println(++num);
    }
}

但是,像是一般的service层却可以使用单例;

service层
@Service
public xx class {
    @Resource
    xxxMapper xxxMapper;
    
    public List(Xxx) getAll( ... ){
        ...
    }
}


Controller层
@Controller
public xx class {
    @Resource
    xxxService xxxService;
    
    Object ...{
        List data = xxxService.getAll(...)
    }
}

以上不涉及到数据修改,xxxMapper、xxxService虽然是成员变量,但是本身只是提供方法,最终的数据是List data = xxxService.getAll(…)并不是成员变量,故是线程安全的;


你可能感兴趣的:(spring,java,spring,spring,boot)