java框架注入是创建对象吗_Spring自动注入(@Autowired)与new实例的区别

Spring自动注入(@Autowired)与new实例的区别

为什么在new对象跟自动注入对象同时使用时会空指针,还有就算new对象怎么处理才不会出现空指针的问题。

根本原因就在当spring框架帮我们管理的时候会帮我们自动的初始化接下来用到的一些属性,而通过用new实例的方法去做,在实例中用到的某些属性可能就需要我们自己去给set值做一个初始化,否则就有可能产生空指针的错误。

1)首先,我们先看一下正常的情况,把管理权交给spring替我们去管理:

在下面代码的第4行将UploadService 注入后,在第18行去对它当中的uploadBlock()方法做了一个调用(注意:这个时候第10行的代码如果是被注释掉的,上面第4行的注入就会生效,反之失效!),我们在18行做引用的时候,在方法中用到了ReadFilePathProperties这一个类,在程序运行过程中框架就帮我们把它给初始化了,就不会出现空指针的错误,程序正常运行。

public classTestController {1@Autowired2 privateFileToByteArrayService fileToByteArrayService;3@Autowired4 privateUploadService uploadService;5@Test6 public void testDemo() throwsIOException {7 //原文件的位置(需根据自己情况修改)

8 String fileSrc = "D:\\tempfile\\elasticsearch-6.4.2.zip";9 byte[] bytes =fileToByteArrayService.fileToBytes(fileSrc);/*** 演示过程中,下面这行代码是否注释掉说明:

* 1.演示通过springboot注入方式去调用UploadService()中的方法需要注释掉。

* 2.演示通过new实例方式进入到UploadService去调用方法出现空指针问题,则需要保留这行代码。

* 3.演示通过new实例方式进入到UploadService去调用方法,通过在UploadService中set值解决问题,则这行代码不能注释掉。*/

10 //UploadService uploadService = new UploadService();

try{11 UploadBlockInputVo param = newUploadBlockInputVo();12 param.setFileName("elasticsearch-6.4.2");13 param.setOffset(0);14 param.setLength(1000000 * 25);15 param.setPartNumber(1);16 param.setSuffix(".zip");17param.setBytes(bytes);18uploadService.uploadBlock(param);

}catch(Exception e) {

e.printStackTrace();

}

}

}

2)接着我们来看通过new对象的形式,不把管理权交给spring。

当我们把第10行注释的代码放开后,程序运行到第10行,这时我们在第4行注入UploadService,在第18行调用它的方法,注入调用方式就会失效,spring框架就不会替我们去管理它,这时候它这儿用到的就是通过第10行的new实例方法去对UploadService中的方法做了调用,而此时uploadBlock()这个方法中的ReadFilePathProperties这个东西并非被spring框架管理,所以就没有被自动地初始化导致报了空指针的错误(注意:如果你这时候通过new方法去调用的方法里面没有需要被初始化的对象属性(下面代码中有解释),则程序依旧正常运行,否则报空指针)。

public classTestController {1@Autowired2 privateFileToByteArrayService fileToByteArrayService;3@Autowired4 privateUploadService uploadService;5@Test6 public void testDemo() throwsIOException {7 //原文件的位置(需根据自己情况修改)

8 String fileSrc = "D:\\tempfile\\elasticsearch-6.4.2.zip";9 byte[] bytes =fileToByteArrayService.fileToBytes(fileSrc);/*** 演示过程中,下面这行代码是否注释掉说明:

* 1.演示通过springboot注入方式去调用UploadService()中的方法需要注释掉。

* 2.演示通过new实例方式进入到UploadService去调用方法出现空指针问题,则需要保留这行代码。

* 3.演示通过new实例方式进入到UploadService去调用方法,通过在UploadService中set值解决问题,则这行代码不能注释掉。*/

10 UploadService uploadService = newUploadService();try{11 UploadBlockInputVo param = newUploadBlockInputVo();12 param.setFileName("elasticsearch-6.4.2");13 param.setOffset(0);14 param.setLength(1000000 * 25);15 param.setPartNumber(1);16 param.setSuffix(".zip");17param.setBytes(bytes);18uploadService.uploadBlock(param);

}catch(Exception e) {

e.printStackTrace();

}

}

}

划重点:

在第18行调用uploadBlock方法时,在uploadService的uploadBlock方法中我们用下面第一行代码,

注释掉第二行,不使用ReadFilePathProperties对象中的方法,这个时候程序也会正常运行。

String uploadPartPath= "D:\\myfile\\elasticsearch-6.4.2Zip";//String uploadPartPath = readFilePathProperties.getPropertisInfo();

(3)最后,我们说一下如果不把管理权交给框架,我们还是想通过new实例去调用实例中的方法,我们应该怎么办。

第一种办法,就是让实例中的调用的方法中不存在使用另一个对象的情况,其实这个问题,上面第2个解释中已经给出了一个答案。第二种办法,就是在uploadBlock方法中给ReadFilePathProperties对象set值,我们自己给他做初始化。通过这两种方式处理过后,即使不由框架为我们管理,也可以达到我们的目的,避免出现空指针的问题。

public classUploadService {

@AutowiredprivateReadFilePathProperties readFilePathProperties;public voidsetReadFilePathProperties(ReadFilePathProperties readFilePathProperties) {this.readFilePathProperties =readFilePathProperties;

}public voiduploadBlock(UploadBlockInputVo uploadBlockInputVo) {//code...

ReadFilePathProperties readFilePathProperties = newReadFilePathProperties();

setReadFilePathProperties(readFilePathProperties);

String uploadPartPath=readFilePathProperties.getPropertisInfo();//code...

}

}

4)总结

在程序的启动时,spring会按照一定的加载链来加载并初始化spring容器中的组件。

例如:A中注入B,B中注入C,在A中调用B,来使用B中的C的方法时,如果不采用自动注入的方式调用,而用new创建B,就会出现空指针异常(因为B中的C并没有被初始化)。如果B中没有注入C,则可以使用new来创建B。

Spring注入bean的顺序,以及Spring如何保证事先加载依赖bean的问题

什么是bean的实例化?什么是bean的初始化?

bean实例化:是bean对象创建的过程。比如使用构造方法new对象,为对象在内存中分配空间。

bean初始化:是为对象中的属性赋值的过程。

场景:Abean中有一个Bbean属性,Bbean中有一个Abean属性,Spring加载依赖bean顺序?

首先初始化A对象实例为例进行讲解整个过程。先说明:基于构造器的循环依赖spring是无法解决的。

1、首先Spring尝试通过ApplicationContext.getBean()方法获取A对象的实例,由于Spring容器中还没有A对象实例,因而其会创建一个A对象。

2、然后发现其依赖了B对象,因而会尝试递归的通过ApplicationContext.getBean()方法获取B对象的实例。

3、但是Spring容器中此时也没有B对象的实例,因而其还是会先创建一个B对象的实例。

4、需要注意这个时间点,此时A对象和B对象都已经创建了,并且保存在Spring容器中了,只不过A对象的属性b和B对象的属性a都还没有设置进去(未初始化)。

5、在前面Spring创建B对象之后,Spring发现B对象依赖了属性A,因而还是会尝试递归的调用ApplicationContext.getBean()方法获取A对象的实例。

6、因为Spring中已经有一个A对象的实例,虽然只是半成品(其属性b还未初始化),但其也还是目标bean,因而会将该A对象的实例返回。

7、此时,B对象的属性a就设置进去了,然后还是ApplicationContext.getBean()方法递归的返回,也就是将B对象的实例返回,此时就会将该实例设置到A对象的属性b中。

8、这个时候,注意A对象的属性b和B对象的属性a都已经设置了目标对象的实例了。

9、此时可能会比较疑惑的是,前面在为对象B设置属性a的时候,这个A类型属性还是个半成品。但是需要注意的是,这个A是一个引用,其本质上还是最开始就实例化的A对象。

10、而在上面这个递归过程的最后,Spring将获取到的B对象实例设置到了A对象的属性b中了。

11、这里的A对象其实和前面设置到实例B中的半成品A对象是同一个对象,其引用地址是同一个,这里为A对象的b属性设置了值,其实也就是为那个半成品的a属性设置了值。

Spring能够轻松的解决属性的循环依赖正式用到了三级缓存,在DefaultSingletonBeanRegistry 中,有着3个map。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implementsSingletonBeanRegistry {private final Map singletonObjects = new ConcurrentHashMap(256);private final Map> singletonFactories = new HashMap(16);private final Map earlySingletonObjects = new HashMap(16);

....略

}

ingletonObjects 它是我们最熟悉的朋友,俗称“ 单例池 ”“ 容器 ”,缓存创建完成单例Bean的地方。

singletonFactories 映射创建Bean的原始工厂

earlySingletonObjects 映射Bean的 早期 引用,也就是说在这个Map里的Bean不是完整的,甚至还不能称之为“ Bean ”,只是一个 Instance .

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为你提供一个简单的登录案例,使用Spring Boot框架和相关注解来实现。 首先,我们需要创建一个名为"UserController"的控制器。该将处理用户登录请求,并返回相应的响应。 ```java @Controller public class UserController { @Autowired private UserService userService; @PostMapping("/login") @ResponseBody public ResponseEntity<String> login(@RequestBody UserDto userDto) { User user = userService.login(userDto.getUsername(), userDto.getPassword()); if (user != null) { return new ResponseEntity<>("Login Successful", HttpStatus.OK); } else { return new ResponseEntity<>("Login Failed", HttpStatus.UNAUTHORIZED); } } } ``` 在上面的代码中,我们使用了@Controller注解来标记该为控制器,@Autowired注入UserService实例,@PostMapping注解用于处理HTTP POST请求,@ResponseBody注解用于将响应体直接返回给客户端,而无需使用模型和视图。@RequestBody注解用于将请求体转换为UserDto对象,然后我们使用UserService实例进行用户登录验证,如果用户存在,则返回成功响应,否则返回失败响应。 接下来,我们需要创建一个UserService,该将处理用户登录逻辑。 ```java @Service public class UserService { @Autowired private UserRepository userRepository; public User login(String username, String password) { User user = userRepository.findByUsername(username); if (user != null && user.getPassword().equals(password)) { return user; } else { return null; } } } ``` 在上面的代码中,我们使用了@Service注解来标记该为服务,@Autowired用于注入UserRepository实例,该将处理用户登录逻辑。我们首先通过调用UserRepository的findByUsername方法来获取用户实例,然后比较用户密码是否与传递的密码相同。如果是,则返回用户实例,否则返回null。 最后,我们需要创建一个名为"UserDto"的数据传输对象,该将用于从请求体中提取用户名和密码。 ```java @Data public class UserDto { private String username; private String password; } ``` 在上面的代码中,我们使用了@Data注解来生成getter和setter方法,以及equals、hashCode和toString方法,这些方法将用于从请求体中提取用户名和密码。 最后,我们需要创建一个名为"UserRepository"的接口,该接口将扩展JpaRepository接口,并提供自定义方法来查询用户实例。 ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { User findByUsername(String username); } ``` 在上面的代码中,我们使用了@Repository注解来标记该接口为存储库接口,该接口将扩展JpaRepository接口,并提供自定义方法findByUsername来查询用户实例。 以上就是使用Spring Boot框架和相关注解实现登录案例的全部内容。希望可以对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值