前面我们了解了Spring Boot项目的搭建,接下来继续学习spring相关的只是
spring有两个很重要的理念,IoC(反转控制),和AOP(面向切面编程)
IoC如何理解?反转控制如果理解?
我们来聊一下,如果应用程序B需要用到应用程序A,我们需要在应用程序B中new一个应用程序A的对象,程序的创建权在应用程序手中,而spring IoC通过配置Bean的方法将应用程序放入到容器中,那么此时应用程序的创建权在IoC容器手中,创建权发生反转,这就叫反转控制。而我们将应用程序放入到容器中,让容器帮助我们创建可以看出IoC的两个作用,①通过描述管理Bean:包括发布和获取Bean实例,②通过描述完成Bean之间的依赖关系
IoC的简介
Spring IoC容器时一个管理Bean的容器,Spring中所有IoC都要实现接口BeanFactory,我们来看BeanFactory接口的源码
getBean方法可以获得对应的Bean实例
isSingleton方法,用来判断Bean在spring IoC中是否为单例,默认是单例
isPrototype方法,用来判断Bean在spring IoC中是否为原型,和isSingleton方法的区别在于,单例指无论获取多少Bean实例都是同一个对象,而原型指每获取一个实例就是一个新的对象
isTypeMatch方法,用来判断Bean是否为指定的类型
getType方法,获取Bean类型
getAliases方法,获取Bean的别名
由于BeanFactory功能不够强大,因此我们使用的spring IoC容器都是ApplicationContext接口的实现类,下图可以看到Application间接继承了BeanFactory,并且在BeanFactory的基础上扩展了消息国际化接口(MessageSource),环境可配置接口(EnvironmentCapable),应用事件发布接口(ApplicationEventPublisher),资源模式解析接口(ResourcePatternResolver)
由于SpringBoot使用注解开发,所以我们也只介绍注解方式,我们要了解AnnotationConfigApplicationContext,通过它获得IoC容器,从而获得Bean实例
我们来练习一下
- 首先定义一个简单的POJO类
- 其次使用java配置类(注解方式)进行配置(目的是将POJO类加入到IOC容器中)
- 最后使用AnnotationConfigApplicationContext获取IoC容器,从而获取Bean对象
定义user类,加入getter和setter方法,以及toString
package com.POJO;
public class user {
private Integer id;
private String username;
private String password;
@Override
public String toString() {
return "user{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
配置类@Configuration声明此类为java配置类,@Bean将方法返回的数据加入到IoC容器中,可以为这个Bean命名,如果不命名,则以方法名命名
package Config;
import com.POJO.user;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
@Bean(name="user")
public user getUser(){
user user = new user();
user.setId(1);
user.setUsername("不背八股睡不着");
user.setPassword("11111111111");
return user;
}
}
最后开整(从IoC中获取Bean)
package com.Application;
import com.POJO.user;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class IoCTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
user user = (user)applicationContext.getBean("user");
System.out.println(user);
}
}
大哥,搞定
我们关注一下第二步,其目的是将user实体类的创建权交给IoC容器,还有其他方式可以让IoC容器装配Bean,而且我们还要解决Bean与Bean之间的关系,下面我们就来继续总结
3.2装配你的Bean
3.2.1通过组件扫描装配我们自定义的Bean
我们先来认识两个注解@Component和@ComponentScan,component可以翻译为组件,componentScan组件扫描,很显然他们俩是配合使用的嘞,我们将@Component注解加在Bean类上,将@ComponentScan注解加在配置类上,想象一下我们在配置类中配置了一个组件扫描器,扫描指定的项目包,如果包中有@Component注解修饰的类则将其放入到Spring IoC容器中
我们举个实例整一整?
POJO类
package com.POJO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
@Value("1")
private Integer id;
@Value("不背八股睡不着")
private String username;
@Value("11111111111")
private String password;
@Override
public String toString() {
return "user{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
配置类
package com.Config;
import com.POJO.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
//扫描的包路径
@ComponentScan("com.POJO")
public class Config {
}
这个不变,这上一小节一样
package com.Application;
import com.Config.Config;
import com.POJO.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class IoCTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
User user = (User)applicationContext.getBean("user");
System.out.println(user);
}
}
@ComponentScan注解的属性
basePackages属性:用于指定要扫描的包路径
ps:@ComponentScan(basePackages={”com.POJO“})
basePackageClasses属性:用于指定要扫描的类
ps:@ComponentScan(basePackageClasses={com.POJO.user})
excludeFilters属性:排除指定的Bean
ps:@ComponentScan(basePackageClasses={com.POJO.user},excludeFilters={@Filters(classes = {Service.class})})
如果我们使用SpringBoot框架,可以减少很多配置,比如@SpringBootApplication注解包含了@Component注解,当然这是后边的内容嘞。
3.2.2自定义第三方Bean
那么前面我们都是自定义类,并且通过SpringIoC容器获取Bean实例对象,但是如果我们想让SpringIoC容器帮我们创建第三方库类,总不能修改第三方库类吧,这个时候我们@Bean注解就排上用处了,我们来举一个例子
假设我们需要springIoC帮助我们创建第三方DBCP数据源
第一步:通过pom.xml文件导入对应的包
第二步:在配置类中使用@Bean将方法(返回数据源的方法)返回值注入到IoC容器中
第三步:测试,从IoC容器中获取数据源
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commonsdbcp2</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
@Bean(name="dataSource")
public DataSource getDataSource(){
//获取数据源的代码,省略了
}