Spring全家桶(官网地址)
Spring Framework
Spring Boot
Spring Cloud
Spring Cloud Data Flow
1.0 Spring Framework
Spring Core
- IOC、AOP
Spring Data Access
- Transactions、Spring MyBatis、Mybatis-Plus
Web Servlet
- Spring MVC
Integration
- Email、Scheduling、AMQP、Security
1.1 Spring IoC:
- Inversion of Control 控制反转,是一种面向对象编程的设计思想
- Dependency Injection 依赖注入,是IoC思想的实现方式
- IoC Container IoC容器,是实现依赖注入的关键,本质上是一个工厂
约定大于配置:
通过配置文件将bean注入容器管理
1.2 简单分析Spring Boot启动类
注解:@SpringBootApplication:
自定义注解所需要的: @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited 下面是SpingBoot核心注解: 配置注解: @SpringBootConfiguration: 点进去查看:本质上就是一个元注解: @Configuration也是一个元注解,(annotation = Component.class)注入(在运行时能使用这个注解)。 组件扫描注解: @ComponentScan:会自动扫描包下的bean装配到容器,它会扫描配置类所在的包和子包的bean(需要有@Controller、@Service、@Repository、它们都是由@Component实现的)加入注解就会被Spring容器管理。 核心注解: @EnableAutoConfiguration:启动自动配置(Spring最核心的注解 )
2.1 Spring 容器管理
通过spring容器获取到bean:
package top.chenxiky.community;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import top.chenxiky.community.dao.AlphaDao;
import top.chenxiky.community.dao.AlphaDaoHibernateImpl;
/**
* 测试类
*
* @author chenxiky
* @version 1.0.0
* @since 2022/10/02/10:37
*/
@SpringBootTest
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = CommunityApp.class) // 配置类
public class CommunityAppTest implements ApplicationContextAware { // 获得容器需实现
// 存储spring容器
private ApplicationContext applicationContext;
/**
* 加载配置类
* ApplicationContext spring容器 是它的子接口(子类扩展更多 通常用子类去)
* HierarchicalBeanFactory 是它的子接口
* BeanFactory就是spring的顶层接口
* spring会扫描到ApplicationContextAware它会调用set方法
*
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Test
public void testApplicationContext() {
// 获取到容器的地址
System.out.println(applicationContext);
// 通过从ApplicationContext这个容器里 获取到自动装配的bean
// 这里可以通过获取父类的方法 也可以精准的获取实现的bean(AlphaDaoHibernateImpl.class)
// 方式一
AlphaDao alphaDao = applicationContext.getBean(AlphaDao.class);
System.out.println("通过父类(接口):"+alphaDao.select());
// 方式二(成功获取到bean)
AlphaDao alphaDao1 = applicationContext.getBean(AlphaDaoHibernateImpl.class);
System.out.println("通过子类:"+alphaDao1.select());
}
}
两个类同时实现了AlphaDao接口的select方法:
此时执行原来的测试代码就会报错:
异常信息:No qualifying bean of type 'top.chenxiky.community.dao.AlphaDao' available: expected single matching bean but found 2: alphaDaoHibernateImpl,alphaDaoMyBatisImpl
解决方案
1.方式一(只获取一个bean):
想运行的bean上加上:@Primary注解,就会优先执行这个bean(只会执行一个)
我们依赖的接口不是它实现的本身,我们需要更改的实现类的时候只需要新建一个实现类,并加上这个注解就可以了。
2.方式二(通过bean名字获取所有bean):
bean的名字是类名首字母小写,类名如果比较长也可以改一下bean的名字 自定义bean的名字@Service("写bean的名字"),可以通过bean的名称获取bean.
具体代码:
@Test
public void testApplicationContext2() {
// 获取到容器的地址
System.out.println(applicationContext);
// 通过从ApplicationContext这个容器里 获取到自动装配的bean(通过注解优先拿到:@Primary)
AlphaDao alphaDao = applicationContext.getBean(AlphaDao.class);
System.out.println(alphaDao.select());
AlphaDao alphaDao2 = applicationContext.getBean("alphaDaoHibernateImpl",AlphaDao.class);
System.out.println(alphaDao2.select());
}
演示bean的创建 初始化 销毁:
package top.chenxiky.community.sevice;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* 业务测试类
*
* @author chenxiky
* @version 1.0.0
* @since 2022/10/02/11:45
*/
@Service
public class AlphaService {
// 证明@PostConstruct是在构造器之后调用
public AlphaService() {
System.out.println("实例化AlphaService...");
}
// 初始化方法
// 容器管理整个bean 创建 初始化 销毁
@PostConstruct // 这个方法会在构造器之后调用 初始化方法通常是在构造器之后调用
public void init() {
System.out.println("初始化AlphaService...");
}
// 销毁方法
@PreDestroy // 在销毁对象之前调用这个方法
public void Destroy() {
System.out.println("销毁AlphaService...");
}
}
测试类:
@Test
public void testBeanManagement() {
AlphaService alphaService = applicationContext.getBean(AlphaService.class);
System.out.println(alphaService);
}
可以清楚的看到bean初始化的过程: 对象是在构造器实例化、再初始化bean 、bean的实例(AlphService@38499e48)、在程序结束的时候 ,最后销毁bean.
spring默认是单例
@Scope("singleton") // 单例
@Scope("prototype") // 多例
采用多例的情况
小结:上面是通过spring去管理自己的bean
2.2 管理第三方的bean
package top.chenxiky.community.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.text.SimpleDateFormat;
/**
* 管理第三方配置类(例如redis 连接池等操作)
*
* @author chenxiky
* @version 1.0.0
* @since 2022/10/02/12:39
*/
@Configuration // 标明是一个配置类 交由spring管理
public class AlphaConfig {
/**
* <p>时间格式化配置类</p>
* <p>方法名就是bean的名字 如果不自定义的话</p>
*/
@Bean
public SimpleDateFormat simpleDateFormat() {
// 实例化这个bean
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
}
测试类:
/**
* 配置类的bean
*/
@Test
public void testBeanConfig() {
SimpleDateFormat simpleDateFormat = applicationContext.getBean(SimpleDateFormat.class);
// 格式化当前日期
System.out.println("格式化当前日期:" + simpleDateFormat.format(new Date()));
}
注意:上面的方式都是通过主动去获取 ,方式不灵活
2.2.1 通过字段注入的方式
通过构造器 、set方法、字段注入bean
@Autowired(按类型注入 byType)
如果需要字段名称注入可结合:@Qualifier注解按照Autowared注入spring会警告,因为它是基于Spring的,不推荐以这种方式注入bean。
缺点:严重依赖Spring,耦合度太高
例子:
@Autowired
private AlphaConfig alphaConfig;
// 注意这里会把这个类型的bean都注入 只想注入某个bean要用@Qualifier结合
@Autowired @Qualifier("alphaDaoHibernateImpl") private AlphaDao alphaDao;
@Resource(按名称注入 byName)
它是java的jar包下的注解,在任何框架下都可以使用,推荐使用这种方式注入bean,它是按照bean名称注入的。
优点:耦合度低。
3.AOP详解
AOP切面编程,不侵入代码,它主要通过动态代理的方式实现的织入。动态代理主要有:JDK动态代理、CGLIB。
默认使用JDK动态代理,利用接口实现代理;只能作用在接口上;
CGLIB 动态代理,利用继承的方式实现代理;可作用在类上也可在接口上;
未完待完善...
4. 自动装配的原理(@EnableAutoConfiguration)详解
未完待续....敬请期待!!