spring-boot关于spring全注解IOC
什么是IOC容器:
Spring IoC 容器是一个管理Bean 的容器,在S pring 的定义中,它要求所有的IoC 容器都需要实
现接口BeanFactory ,它是一个顶级容器接口
IoC 是一种通过描述来生成或者获取对象的技术,而这个技术不是Spring 甚至不是Java 独有的。
对于Java 初学者更多的时候所熟悉的是使用new 关键字来创建对象,
spring-boot和spring中IOC容器的区别
Spring 中,它是通过描述来创建对象。只是S pring Boot 并不建议使用XML ,而是通过注解的描述生成对象,
所以他的原理还是一样的。
IOC容器的作用:
的班级、同学和老师这3 个对象关系,我们需要一个容器。在S pring 中把每一个
需要管理的对象称为Spring Bean (简称Bean ),而Spring 管理这些Bean 的容器,被我们称为S pring
IoC 容器(或者简称IoC 容器) 。IoC 容器需要具备两个基本的功能:
•@通过描述管理Bean , 包括发布和获取Bean; .
@通过描述完成Bean 之间的依赖关系。
简单的注入Bean
在Spring 中允许我们通过XML 或者Java 配置文件装配Bean , 但是由于Spring Boot 是基于注
解的方式,所以通过注解方式实现
需要加载近IOC容器的累pojo
public class User {
private String name;
private int id; public User(String name, int id) {
this.name = name;
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
}
}
添加bean配置累:
@ Configuration 代表这是一个Java 配置文件, Sprin g 的容器会根据
它来生成IoC 容器去装配Bean;
@Configuration
public class TestConfig {
@Bean("user")
public User userTest(){
return new User("quan",23);
}
}
这里@bean注解的类方法,将类方法的返回值加载到ioc容器当中,其中里面的字符串代表注入容器Bean的名字。不写默认是方法名称
可以通过下面的测试方法进行测试:
public class userTest {
// private Logger logger = LoggerFactory.getLogger(getClass());
private static Logger logger = LoggerFactory.getLogger(userTest.class); public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
User user = (User) context.getBean("user");
logger.info(user.getName());
}
}
springboot中更方便的装配Bean:
11通过扫描装配的Bean
如果一个个的Bean 使用注解@Bean 注入Spring loC 容器中,那将是一件很麻烦的事情。
#####################################################################
Spring 还允许我们进行扫描装配Bean 到loC 容器中,对于扫描装配而言使用的注解是
@Component
@ComponentScan 。
@Component 是标明l哪个类被扫描进入Spring IoC 容器,
@ComponentScan则是标明采用何种策略去扫描装配Bean
#########################################################################
User:
/*
这个注解表面这个类被springIOC容器扫描装配
user是作为Bean的名称,如果不配置就按照你的类名第一个小写,其他不变
*/
@Component("user")
public class User {
// 指定具体的值,
@Value("quan")
private String name;
@Value("12")
private int id; public User() {
} public User(String name, int id) {
this.name = name;
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
}
}
注意:这里需要加入无参构造函数!!!!!!!!!!!!注入bean需要一个无参构造函数
配置累:,后面可以不用了。
@Configuration
//默认只会扫描这个类所在的包或子包
@ComponentScan
public class TestConfig {
}
测试结果也是一样的
@ComponentScan允许自定义扫描包的:
将User放到com.quan.learning.DAO下之后:
@Configuration
//默认只会扫描这个类所在的包或子包
@ComponentScan("com.quan.learning.DAO")
public class TestConfig {
}
也是可以扫秒到的
可以使用正则表达式匹配;
@Configuration
//默认只会扫描这个类所在的包或子包
@ComponentScan("com.quan.learning.*")
public class TestConfig {
}
不想加载服务类的bean
@Configuration
//默认只会扫描这个类所在的包或子包
@ComponentScan(value = "com.quan.learning.*",excludeFilters = {@Filter(classes = {Service.class})})
public class TestConfig {
}
@Filter的源码;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter {
FilterType type() default FilterType.ANNOTATION; @AliasFor("classes")
Class<?>[] value() default {}; @AliasFor("value")
Class<?>[] classes() default {}; String[] pattern() default {};
}
测试累加上:
UserService service = (UserService) context.getBean("userService");
自定义第三方bean“
加入第三方依赖:
<!-- 自定义第三方bean-->
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
自定义BEan
@Configuration
//默认只会扫描这个类所在的包或子包
@ComponentScan(value = "com.quan.learning.*",excludeFilters = {@Filter(classes = {Service.class})})
public class TestConfig { @Bean("datasource")
public DataSource getDataSource(){
Properties properties = new Properties();
properties.setProperty("driver","com.mysql.jdbc.Driver");
properties.setProperty("url","jdbc:mysql://localhost:3306/ApolloConfigDB");
properties.setProperty("username","root");
properties.setProperty("password","1997");
DataSource dataSource = null;
try {
dataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
return dataSource;
}
}
依赖的注入:
装配bean之后就是要获取bean,那么获取bean的过程就是依赖的注入Dependence injection DI
/*
编程思路:定义动物和人的接口层,分别去实现这两个接口
在实现人的接口的时候,需要加入animal的属性,所以需要引入依赖
*/
//动物接口
public interface Animal {
public void use();
} ################
//人的接口
public interface Person {
public void service(); } ###############
@Component
public class Dog implements Animal{
@Override
public void use() {
System.out.println(Dog.class.getSimpleName()+"kanmen");
}
} ##############
@Component
public class Rpersion implements Person{
@Autowired
private Animal animal = null; @Override
public void service() {
this.animal.use();
}
}
test一下:
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfig.class);
Person person = context.getBean(Rpersion.class);
person.service();
}
//根据属性的类型找到对应的Bean进行注入,Dog是动物的一个实现类,
//所以将Dog的实例注入到Rpersion中,这样使用Rpersion的时候就能够使用Dog实例来服务
@Autowired 注解
如果我们加入多一个animal的实现类,继续单单使用@Autowired的话,
@Component
public class Cat implements Animal{
@Override
public void use() {
System.out.println("catcat");
}
}
找到两个实例,springboot并不能判断我们要注入的是cat还是dog
通过修改属性的名字即可,类型不变:
这鸭子就可以注入成功了,因为如果有两个同样类型的实例,@Autowired会根据属性名称去匹配
如果允许所加载的bean可以为null,一是使用上面的直接等于的方法,
另一种推荐用法为
@Autowired(required = false)
private Animal dog ;
不修改属性名消除歧义的方法:
@Primary:一般在装配的bean上,解决如果有多个同一个类型的实例,优先注入给这个标注的bean
@Component
@Primary
public class Cat implements Animal{
@Override
public void use() {
System.out.println("catcat");
}
}
这样子不会产生奇异,想使用那个就往那个类加上@Primary
如果cat已经使用了@Primary,那我们需要用dog,这时候就要使用
@Qualify
和@Autowired一起实现 IOC容器里面bean名字的查询,不再需要修改属性名字
带有参数的构造方法的装配
他的构造方法带有参数,需要注入其他bean依赖
因为默认
@Component
public class Rpersion implements Person{ private Animal animal ; public Rpersion(@Autowired @Qualifier("dog") Animal animal) {
this.animal = animal;
} @Override
public void service() {
this.animal.use();
}
}
Bean的生命周期:
@Component
public class Rpersion implements Person , BeanNameAware, BeanFactoryAware,
ApplicationContextAware, InitializingBean, DisposableBean { private Animal animal = null; @Override
public void service() {
this.animal.use();
} @Autowired(required = false)
@Qualifier("dog")
public void setAnimal(Animal animal) {
System.out.println("依赖注入!!!!");
this.animal = animal;
} //接口;BeanNameAware
@Override
public void setBeanName(String s) {
System.out.println(this.getClass().getSimpleName()+" 接口;BeanNameAware=setBeanName");
} //接口:BeanFactoryAware
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println(this.getClass().getSimpleName()+" 接口;BeanFactoryAware=setBeanFactory");
} //接口:ApplicationContextAware
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println(this.getClass().getSimpleName()+" 接口;ApplicationContextAware=setApplicationContext");
} //接口:InitializingBean
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(this.getClass().getSimpleName()+" 接口;InitializingBean=afterPropertiesSet");
} //接口:DisposableBean
@Override
public void destroy() throws Exception {
System.out.println(this.getClass().getSimpleName()+" 接口;DisposableBean=destroy");
} //定义初始化方法
@PostConstruct
public void init(){
System.out.println(this.getClass().getSimpleName()+" 注解;@PostConstruct=init");
} //定义销毁方法
@PreDestroy
public void predestory(){
System.out.println(this.getClass().getSimpleName()+" 注解; @PreDestroy=predestory");
} }
测试结果:
Rpersion 接口;BeanNameAware=setBeanName
Rpersion 接口;BeanFactoryAware=setBeanFactory
Rpersion 接口;ApplicationContextAware=setApplicationContext
Rpersion 注解;@PostConstruct=init
Rpersion 接口;InitializingBean=afterPropertiesSet
Dogkanmen
16:42:20.949 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@6073f712, started on Fri Aug 07 16:42:20 CST 2020
Rpersion 注解; @PreDestroy=predestory
Rpersion 接口;DisposableBean=destroy
当我们使用第三方bean的时候,可能会使用到@bean注解,可以通过注解去自定义初始化或销毁的方法:
@Bean(value = "datasource",initMethod = "init",destroyMethod = "destory")
条件装载bean:
场景:当用户没有配置数据库的四个变量,或者不完整的时候,不对bean进行装配,因为装配之后用的时候回有错误
这时候可以使用@Conditional注解完成
先编写装配条件类:
public class DatabaseConditional implements Condition { /**
*
* @param conditionContext 条件上下文
* @param annotatedTypeMetadata 注释的类型的元数据
* @return ture装配,false不装配
*/
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();//获取环境配置
return environment.containsProperty("driver")
&&environment.containsProperty("url")
&&environment.containsProperty("username")
&&environment.containsProperty("password");
}
}
注意:条件类必须实现接口Condition
在需要加入条件注解的类上加入,并且需要设置条件类属性@Conditional(DatabaseConditional.class)
@Configuration
@PropertySource(value = {"classpath:jdbc.properties"},ignoreResourceNotFound = true)
@ComponentScan(value = "com.quan.learning.*",excludeFilters = {@Filter(classes = {Service.class})} )
public class TestConfig { @Bean(value = "datasource")
@Conditional(DatabaseConditional.class)
public DataSource getDataSource(
@Value("${driver}") String driver,
@Value("${url}") String url,
@Value("${username}") String username,
@Value("${password}") String password ){
Properties properties = new Properties();
properties.setProperty("driver",driver);
properties.setProperty("url",url);
properties.setProperty("username",username);
properties.setProperty("password",password);
DataSource dataSource = null;
try {
dataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
return dataSource;
}
}
如果配置文件里面的值不存在的话,这时候就不会再装配这个类,
注解源码集合########################
@Bean
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
注解在方法上,和注解上
ElementType.ANNOTATION_TYPE 只可以标记注解类型
@Con
spring-boot关于spring全注解IOC的更多相关文章
- spring boot(7)-mybatis全注解化
关于配置数据库可以参考上一篇文章,这里只讲mybatis pom.xml <!-- 引入mybatis --> <dependency> <groupId>org. ...
- Spring Boot (9) mybatis全注解化
ORM对比图 框架对比 Spring JDBC Spring Data Jpa Mybatis 性能 性能最好 性能最差 居中 代码量 多 少 多 学习成本 低 高 居中 推荐指数 ❤❤❤ ❤❤❤❤❤ ...
- spring boot + vue + element-ui全栈开发入门——开篇
最近经常看到很多java程序员朋友还在使用Spring 3.x,Spring MVC(struts),JSP.jQuery等这样传统技术.其实,我并不认为这些传统技术不好,而我想表达的是,技术的新旧程 ...
- spring boot + vue + element-ui全栈开发入门——基于Electron桌面应用开发
前言 Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库. Electron通过将Chromium和Node.js合并到同一个运行时环 ...
- Jhipster 一个Spring Boot + Angular/React 全栈框架
Jhipster 一个Spring Boot + Angular/React 全栈框架: https://www.jhipster.tech/
- spring boot + vue + element-ui全栈开发入门
今天想弄弄element-ui 然后就在网上找了个例子 感觉还是可以用的 第一步是完成了 果断 拿过来 放到我这里这 下面直接是连接 点进去 就可以用啊 本想着不用vue 直接导入连接 ...
- Spring Boot整合MyBatis(非注解版)
Spring Boot整合MyBatis(非注解版),开发时采用的时IDEA,JDK1.8 直接上图: 文件夹不存在,创建一个新的路径文件夹 创建完成目录结构如下: 本人第一步习惯先把需要的包结构创建 ...
- Spring Boot 实战 —— MyBatis(注解版)使用方法
原文链接: Spring Boot 实战 -- MyBatis(注解版)使用方法 简介 MyBatis 官网 是这么介绍它自己的: MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过 ...
- spring boot的一些常用注解
spring boot的一些常用注解: 使用@SpringBootApplication注释: 许多Spring Boot开发人员喜欢他们的应用程序使用自动配置,组件扫描,并能够在其“应用程序类”上定 ...
- Spring Boot的27个注解【核心】
导读[约定大于配置] Spring Boot方式的项目开发已经逐步成为Java应用开发领域的主流框架,它不仅可以方便地创建生产级的Spring应用程序,还能轻松地通过一些注解配置与目前比较火热的微服务 ...
随机推荐
- simple js
simple js 题目描述:小宁发现了一个网页,但却一直输不对密码.(Flag格式为 Cyberpeace{xxxxxxxxx} ) 打开题目后,有一个Enter password框,要求输入密码, ...
- selenium+python自动化103-一闪而过的dialog如何定位
前言 web页面操作的时候经常会遇到一闪而过的 dialog 消息,这些提示语一般只出现了几秒,过后元素节点就会在DOM中消失了. 本篇讲解下用chrome 浏览器如何定位一闪而过的 dialog 消 ...
- 树莓派4B安装 百度飞桨paddlelite 做视频检测 (一、环境安装)
前言: 当前准备重新在树莓派4B8G 上面搭载训练模型进行识别检测,训练采用了百度飞桨的PaddleX再也不用为训练部署环境各种报错发愁了,推荐大家使用. 关于在树莓派4B上面paddlelite的文 ...
- 二级py--day3
二级PY--day3 1.结构化程序设计方法主要原则:自顶向下.逐步求精.模块化.限制使用goto语句 2.三种控制结构:顺序.选择和重复(循环) 3.结构化程序强调:程序的可复用性 4.结构化程序设 ...
- petite-vue源码剖析-双向绑定`v-model`的工作原理
前言 双向绑定v-model不仅仅是对可编辑HTML元素(select, input, textarea和附带[contenteditable=true])同时附加v-bind和v-on,而且还能利用 ...
- php 代码上线
1:php软件界面点击Tools按步骤进行即可 2:二步 3:三步 user name 为root 4:四步 5:五步
- tp 5 三级联动查询(自写)
思路: 1.定义路由 2.查询顶级分类(pid=0)发送至制图 3.循环展示 4.给顶级分类下拉框绑定内容改变事件(JS:onchange.JQ:change) 5.获取到选中的option的valu ...
- Wireshark抓包工具解析HTTPS包
目录 一.遇到的问题 二.解决方案 1. 动态生成签名证书 2. Wireshark配置 3. 最终效果 一.遇到的问题 本学期的计算机网络课程需要使用到Wireshark抓包工具进行网络抓包实验,原 ...
- ROS路由器DHCP地址不够使用解决办法!
由于这段时间公司使用ROS6.2+AC控制器+AP的方案做了公WIFI覆盖,但最近发现地址被用完. 如果使用默认的地址192.168.1.1-192.168.8.254,最多只有254个地址可用,但内 ...
- 12、mysql的事务日志
mysql的事务日志 事务有4种特性:原子性.一致性.隔离性和持久性.那么事务的四种特性到底是基于什么机制实现呢? 事务的隔离性由锁机制实现. 事务的原子性.一致性和持久性由事务的redo日志和und ...