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

浙公网安备 33010602011771号