当前位置: 首页 > news >正文

Spring IoCDI补充

IoC详解

        IoC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象.也就是bean的存储.

        Bean的存储

        共有两类注解类型可以实现Bean的存储:

        1. 类注解:@Controller、@Service、@Repository、@Component、@Configuration.

        2. 方法注解:@Bean.

        @Controller(控制器存储)

        使用@Controller存储Bean的代码如下:

@Controller
public class UserController {public void sayHi() {System.out.println("hi,UserController");}
}

        在启动类中,从Spring IoC容器中获取对象

    public static void main(String[] args) {ApplicationContext context = SpringApplication.run(IoCApplication.class, args);UserController bean = context.getBean(UserController.class);bean.sayHi();}

        Spring容器中已包含这个Bean.

        @Service(服务存储)

        使用@Service存储Bean的代码如下所示:

@Service
public class UserService {public void sayHi(){System.out.println("hi,UserService");}
}public static void main(String[] args) {ApplicationContext context = SpringApplication.run(IoCApplication.class, args);UserService bean = context.getBean(UserService.class);bean.sayHi();}

        

        @Repository(仓库存储)
@Repository
public class UserRepository {public void sayHi() {System.out.println("Hi, UserRepository~");}
}public static void main(String[] args) {ApplicationContext context = SpringApplication.run(IoCApplication.class, args);UserRepository bean = context.getBean(UserRepository.class);bean.sayHi();}

        @Component(组件存储)
@Component
public class UserComponent {public void sayHi() {System.out.println("Hi, UserComponent");}
}public static void main(String[] args) {ApplicationContext context = SpringApplication.run(IoCApplication.class, args);UserComponent bean = context.getBean(UserComponent.class);bean.sayHi();}

        @Configuration(配置存储)
@Configuration
public class UserConfiguration {public void sayHi() {System.out.println("Hi,UserConfiguration");}
}    
public static void main(String[] args) {ApplicationContext context = SpringApplication.run(IoCApplication.class, args);UserConfiguration bean = context.getBean(UserConfiguration.class);bean.sayHi();}

        为什么要这么多注解?

        从上面可以观察到,这些注解的用法看起来大差不差.但是这些注解与应⽤分层是呼应的.让程序员看到类注解之后,就能直接了解当前类的⽤途.

        @Controller 控制层,接受请求,对请求进行处理,并进行相应.

        @Service 业务逻辑层,处理具体的业务逻辑.

        @Repository 数据访问层,也称为持久层,负责数据访问操作.

        @Configuration 配置层,处理项⽬中的⼀些配置信息.

        查看 @Controller/@Service/@Repository/@Configuration等注解的源码发现:他们的注解都包含@Component,也就是这些注解都是@Component的"子类".@Component的功能,这些注解都包含.

        @Controller,@Service和@Repository⽤于更具体的⽤例(分别在控制层,业务逻辑层,持久化层),在开发过程中,如果你要在业务逻辑层使⽤@Componen或@Service,显然@Service是更好的选择.

        方法注解@Bean

        类注解是注解在某个类上的,但是这样做有两个问题:

        1.在使用外部包的类时,无法使用类注解对外部包的类进行注解.

        2.一个类需要多个对象时,类注解只会产生一个对象.

        在上述的两个场合,就需要使用方法注解@Bean.

        观察@Bean如何使用:

public class BeanConfig {@Beanpublic UserInfo userInfo(){UserInfo userInfo = new UserInfo();userInfo.setAge(18);userInfo.setName("zhangsan");return userInfo;}
}
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.springboot.ioc.model.UserInfo' availableat org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1148)at com.springboot.ioc.IoCApplication.main(IoCApplication.java:18)

        直接使用,并尝试获取对象时报错,NoSuchBeanDefinitionException根据后续信息判断出,这里@Bean注解没有成功添加Bean到容器中.

        方法注解要配合类注解使用

        在Spring框架的设计中,⽅法注解 @Bean要配合类注解才能将对象正常的存储到Spring容器中,如下代码所⽰:

@Component
public class BeanConfig {@Beanpublic UserInfo userInfo(){UserInfo userInfo = new UserInfo();userInfo.setAge(18);userInfo.setName("zhangsan");return userInfo;}
}

        成功获取到对象.

        定义多个对象
@Component
public class BeanConfig {@Beanpublic UserInfo userInfo(){UserInfo userInfo = new UserInfo();userInfo.setAge(18);userInfo.setName("zhangsan");return userInfo;}@Beanpublic UserInfo user(){UserInfo userInfo = new UserInfo();userInfo.setAge(18);userInfo.setName("lisi");return userInfo;}@Beanpublic UserInfo userInfo1(){UserInfo userInfo = new UserInfo();userInfo.setAge(18);userInfo.setName("wangwu");return userInfo;}
}
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.springboot.ioc.model.UserInfo' available: expected single matching bean but found 3: userInfo,user,userInfo1at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1287)at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:483)at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:338)at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1148)at com.springboot.ioc.IoCApplication.main(IoCApplication.java:18)

        此时获取对象又报错了,NoUniqueBeanDefinitionException,根据报错信息判断出,Spring容器中包含多个Bean,但是Spring无法判断选择哪一个.此时我们只需要指定获取哪个Bean即可.

    public static void main(String[] args) {ApplicationContext context = SpringApplication.run(IoCApplication.class, args);//指定获取名为user的对象UserInfo bean = context.getBean("user",UserInfo.class);System.out.println(bean);}

        在指定获取之后,程序成功允许并获得了正确的结果.

        重命名Bean

        可以通过name属性给Bean对象进行重命名操作.

    //将user重命名为UUUUUUU@Bean(name = {"UUUUUUU","user"})public UserInfo user(){UserInfo userInfo = new UserInfo();userInfo.setAge(18);userInfo.setName("lisi");return userInfo;}public static void main(String[] args) {ApplicationContext context = SpringApplication.run(IoCApplication.class, args);UserInfo bean = context.getBean("UUUUUUU",UserInfo.class);System.out.println(bean);}

        重命名并使用新的名称指定获取成功.

        扫描路径

        项目中的代码并不是所有代码都能被Spring扫描到的,程序被Spring扫描并管理需要满足以下条件:

        1.被Spring扫描到,Spring默认扫描路径为启动类所在的目录包含子目录.可以通过@ComponentScan(basePackage="")进行修改.

        2.类需要配合五大注解使用.

DI详解

        依赖注⼊是⼀个过程,是指IoC容器在创建Bean时,去提供运⾏时所依赖的资源,⽽资源指的就是对象.在之前程序案例中,使⽤了@Autowired 这个注解,完成了依赖注⼊的操作.

        依赖注入,Spring也提供了三种方案:

        1.属性注入

        2.构造方法注入

        3.Setter注入

        属性注入

        属性注⼊是使用@Autowired实现的,将Service类注⼊到Controller类中:

@Service
public class UserService {public void sayHi(){System.out.println("hi,UserService");}
}
@Controller
public class UserController {//属性注入@Autowiredprivate UserService userService;public void sayHi() {System.out.println("hi,UserController");userService.sayHi();}
}

        注入成功,代码正确执行.

        构造方法注入

        依旧将Service类注⼊到Controller类中:

@Controller
public class UserController {private UserService userService;public UserController(UserService userService) {this.userService = userService;}public void sayHi() {System.out.println("hi,UserController");userService.sayHi();}
}

        直接写出包含Service的构造方法,即可正确注入.

        但是如果类中包含多个构造方法,那么就会出现错误.

@Controller
public class UserController {private UserService userService;public UserController() {}public UserController(UserService userService) {this.userService = userService;}public void sayHi() {System.out.println("hi,UserController");userService.sayHi();}
}
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.springboot.ioc.service.UserService.sayHi()" because "this.userService" is nullat com.springboot.ioc.controller.UserController.sayHi(UserController.java:20)at com.springboot.ioc.IoCApplication.main(IoCApplication.java:19)

        抛出了空指针异常,说明Spring直接使用了无参数的构造方法,如果想让Spring使用我们提供的包含Serveice的构造方法,需要标上@Autowired注解.

@Controller
public class UserController {private UserService userService;public UserController() {}@Autowiredpublic UserController(UserService userService) {this.userService = userService;}public void sayHi() {System.out.println("hi,UserController");userService.sayHi();}
}

        包含多个构造方法时:

@Controller
public class UserController {private UserService userService;private UserConfiguration userConfiguration;//    public UserController() {
//    }public UserController(UserService userService) {this.userService = userService;}public UserController(UserService userService, UserConfiguration userConfiguration) {this.userService = userService;this.userConfiguration = userConfiguration;}public void sayHi() {System.out.println("hi,UserController");userService.sayHi();}
}
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController' defined in file [E:\Java\IoC\target\classes\com\springboot\ioc\controller\UserController.class]: Failed to instantiate [com.springboot.ioc.controller.UserController]: No default constructor foundat org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1306) ~[spring-beans-6.0.4.jar:6.0.4]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1198) ~[spring-beans-6.0.4.jar:6.0.4]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[spring-beans-6.0.4.jar:6.0.4]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-6.0.4.jar:6.0.4]at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.4.jar:6.0.4]at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.4.jar:6.0.4]at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.4.jar:6.0.4]at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.4.jar:6.0.4]at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) ~[spring-beans-6.0.4.jar:6.0.4]at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915) ~[spring-context-6.0.4.jar:6.0.4]at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[spring-context-6.0.4.jar:6.0.4]at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.0.2.jar:3.0.2]at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[spring-boot-3.0.2.jar:3.0.2]at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) ~[spring-boot-3.0.2.jar:3.0.2]at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-3.0.2.jar:3.0.2]at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[spring-boot-3.0.2.jar:3.0.2]at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[spring-boot-3.0.2.jar:3.0.2]at com.springboot.ioc.IoCApplication.main(IoCApplication.java:17) ~[classes/:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.springboot.ioc.controller.UserController]: No default constructor foundat org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83) ~[spring-beans-6.0.4.jar:6.0.4]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1300) ~[spring-beans-6.0.4.jar:6.0.4]... 17 common frames omitted
Caused by: java.lang.NoSuchMethodException: com.springboot.ioc.controller.UserController.<init>()at java.base/java.lang.Class.getConstructor0(Class.java:3585) ~[na:na]at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2754) ~[na:na]at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:79) ~[spring-beans-6.0.4.jar:6.0.4]... 18 common frames omitted

        分析报错信息,得出是因为没有默认的构造函数导致的.此时给我们需要的构造函数加上@Autowired注解即可.

        Setter注入

        Setter注⼊和属性的Setter⽅法实现类似,只不过在设置set⽅法的时候需要加上@Autowired注解,如下代码所⽰:

@Controller
public class UserController {private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void sayHi() {System.out.println("hi,UserController");userService.sayHi();}
}

        三种注入的优缺点分析

        属性注⼊
优点:简洁,使⽤⽅便
缺点:
1.只能⽤于IoC容器,如果是⾮IoC容器不可⽤,并且只有在使⽤的时候才会出现NPE(空指针异常)
2.不能注⼊⼀个Final修饰的属性

        构造函数注⼊(Spring4.X推荐)
优点:
1.可以注⼊final修饰的属性
2.注⼊的对象不会被修改
3.依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法
是在类加载阶段就会执⾏的⽅法.
4.通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的.
缺点:注⼊多个对象时,代码会⽐较繁琐

        Setter注⼊(Spring3.X推荐)
优点:⽅便在类实例之后,重新对该对象进⾏配置或者注⼊
缺点:
1.不能注⼊⼀个Final修饰的属性.
2.注⼊对象可能会被改变,因为setter⽅法可能会被多次调⽤,就有被修改的⻛险.

        @Autowired存在问题

        Autowired会先尝试获取与所修饰的变量同名的Bean,当不存在同名的Bean时,尝试获取同类型的Bean.当同一类型存在多个Bean时,使用@Autowired就会存在问题:

@Controller
public class UserController {@Autowiredprivate UserInfo userInfo2;public void sayHi() {System.out.println("hi,UserController");System.out.println(userInfo2);}
}

        报错的原因是存在非唯一的bean对象.

        解决方案:

        使用@Primary

        使用@Primary来标识默认的Bean对象.

    @Primary@Beanpublic UserInfo userInfo(){UserInfo userInfo = new UserInfo();userInfo.setAge(18);userInfo.setName("zhangsan");return userInfo;}

        使用@Qualifier

        使用@Qualifier注解:指定当前要注⼊的bean对象.在@Qualifier的value属性中,指定注⼊的bean的名称.

public class UserController {//指定获取变量名为user的Bean@Qualifier("user")@Autowiredprivate UserInfo userInfo2;public void sayHi() {System.out.println("hi,UserController");System.out.println(userInfo2);}
}

        使⽤@Resource

        使⽤@Resource注解:是按照bean的名称进⾏注⼊.通过name属性指定要注⼊的bean的名称.

public class UserController {//获取userInfo1@Resource(name = "userInfo1")private UserInfo userInfo2;public void sayHi() {System.out.println("hi,UserController");System.out.println(userInfo2);}
}

        @Autowired与@Resource的区别:

        @Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解.

        @Autowired默认是按照类型注⼊,而@Resource是按照名称注⼊.相比于@Autowired来说,@Resource⽀持更多的参数设置,例如name设置,根据名称获取Bean.

http://www.dtcms.com/a/503889.html

相关文章:

  • debug:内部设备故障
  • 数字电路 | 运放及放大器交越失真现象解析
  • dedecms手机网站制作wordpress app 生成6
  • 网站营销计划书免费w网站建设
  • 网站建设找哪家公司19手机网站
  • SpringBoot的自动配置魔法——小白的内功修炼
  • dw和vs做网站舟山网大海网
  • 给帅哥做奴视频网站排名前十的小说
  • Netty网络架构与Reactor模式深度解析
  • 大型网站设计首页实例wordpress系统安装教程
  • Spring Boot 3零基础教程,WEB 开发 内容协商机制 笔记33
  • 基于单片机的PWM三基色LED灯控制器设计与无线调色系统
  • 网站开发的价格产品图册设计公司
  • 量化策略如何处理不同周期指标出现矛盾信号的情况
  • 建网站要注意些什么html页面网站建设中
  • 学校能建设网站吗商城平台是什么
  • 厦门市建设工程造价协会官方网站重庆市建设局网站
  • vue3 + mars3D 三分钟画一个地球
  • 如何比较网站wordpress 文章多图
  • 前端框架文档新思路:基于源码解析的自动化方案
  • 做微网站需要哪种公众号wordpress做菜鸟教程
  • Matlab之App Designer 如何调整输出参数的小数点精度
  • 第 13 章:Spring AI Alibaba MCP 与 Nacos3 — 企业级MCP服务
  • 备案名称和网站名称wordpress 问答 主题 knowhow
  • 咨询行业网站制作查营业执照怎么查询
  • Kubernetes Pod 调度详解
  • 做网站是先做界面还是先做后台how to use wordpress ninja forms
  • AI学习日记——PyTorch深度学习快速入门:从NumPy到张量的平滑过渡
  • 深圳做app网站公司岳阳建设网站的公司
  • 数组分块|裴蜀定理