Spring使用了哪些设计原则
OCP开闭原则,DIP依赖倒置原则,控制反转IoC(新的设计模式)
IOC的实现方法:依赖注入,依赖注入有两种方式,set方法注入,构造方法注入
Spring的八大模块
Spring Core:通过IoC实现对Bean的创建和管理,主要组件是BeanFactory接口。ApplicationContext继承了BeanFactory接口,提供了AOP等功能,它的具体实现有ClassPathXmlApplicationContext,AnnotationConfigApplicationContext等等。
Spring AOP模块:实现面向切面编程,一方面可以分离非业务代码,另一方面可以进行横向的功能扩展。如自定义拦截器,日志,事务等等。
Spinrg ORM:用于集成第三方的ORM框架,如MyBatis(实现对象和数据库的转换,简化数据库操作,将sql语句与java代码分离)
Spring Web MVC:为Web应用提供了一个表现层框架。
Spring入门
Spring如何创建对象:通过反射获取类,使用根据类创建对象,然后将对象放入容器(Map)中。
Class clazz = Class.forName("com.powernode.spring6.bean.User");
Object obj = clazz.newInstance();
Spring的日志框架:log4j(log4j2)
SpringIoC的实现方式:依赖注入
依赖注入的两种方法:set方法和构造方法
Set方法:
public class UserService {
private UserDao userDao;
// 使用set方式注入,必须提供set方法。
// 反射机制要调用这个方法给属性赋值的。
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.insert();
}
}
//调用属性的SetUserDao方法注入
//bean的名字
构造方法:
public class OrderService {
private OrderDao orderDao;
// 通过反射机制调用构造方法给属性赋值
public OrderService(OrderDao orderDao) {
this.orderDao = orderDao;
}
public void delete(){
orderDao.deleteById();
}
}
注入简单类型value:基本类型及包装,String,Date,Number等
20
注入级联属性:给属性的属性赋值
注入数组:array
注入List集合:list
注入Set集合:set
注入Map集合:map entry
使用P命名空间可以简化Set注入配置
使用C命名空间可以简化构造方法注入配置
使用Util命名空间可以复用配置
Bean的作用域 scope
单例bean:(默认)在Spring容器初始化时创建
多例bean:调用getBean()方法时创建
request:一个请求对应一个bean
session:一个会话对应一个bean
GoF之工厂模式
1.工厂方法模式:每个产品对应要给factory
2.抽象工厂模式:每个产品系列对应一个factory
bean的实例化方式
1.使用默认构造方法
2.使用工厂方法
3.通过FactoryBean接口构造
BeanFacotry和FactoryBean的区别:
beanFactory是创建bean的抽象工厂,factorybean是一个工厂bean,可以复制Spring实例化其他对象。
bean的生命周期
只有单例bean才会被Spring管理完整的生命周期,多例bean Spring只复制创建。
1.实例化bean
2.属性赋值
初始化前before 如果配置了后处理器
3.初始化bean
初始化后after
4.使用bean
5.销毁bean context.close()
如何使用后处理器:
实现BeanPostPorcessor接口,然后配置为bean
Spring Bean的循环依赖问题
A依赖B对象,而B又依赖A对象
Spring通过三级缓存解决循环依赖问题。
原理是将bean的实例化和属性赋值分开
一级缓存:存放完整单例对象
二级缓存:存放早期单例对象
三级缓存:存放单例对象的工厂对象,工厂对象可以创建代理对象,解决AOP的循环依赖
简单来说
Spring使用三级缓存解决循环依赖 - 掘金 (juejin.cn)
源码级详解Spring的三级缓存,循环依赖的处理流程 - 掘金 (juejin.cn)
创建bean时:
1.先将beanA实例化,然后将beanA的工厂对象放入三级缓存
2.对beanA进行属性赋值,发现依赖beanB,然后执行创建B的过程
4.beanB进行属性赋值,发现依赖A,先从一级缓存中查找,没有,再从二级缓存中查找,没有,再从三级缓存中查找,然后通过beanA的工厂对象创建beanA,将beanA放入二级缓存,从三级缓存中移除。
5.把不完整的beanA注入beanB中并进行初始化,然后将B放入一级缓存。
6.此时A从一级缓存中获取B对象,然后进行属性赋值和初始化
7.最后将beanA放入一级缓存。
Spring IoC注解式开发
创建Bean的注解:
@Component ,
@Controller @Service @Repository都是@Component的别名
表现层用@Controller,业务层用@Service,持久层用@Repository
依赖注入的注解:
@Value 简单类型,@Autowired 默认按照类型注入,可以和@Qualifier结合实现按名称注入,@Resource(属于jdk扩展包的注解,Autowired属于Spring的注解)默认按照名称注入,找不到时再根据类型注入。
配置文件的注解:
使用配置类代替spring配置文件
@Configuration
@ComponentScan({"com.powernode.spring6.dao", "com.powernode.spring6.service"})
public class Spring6Configuration {
}
创建容器时使用AnnotationConfigApplicationContext,而不是ClassPathXmlApplicationContext。
@Test
public void testNoXml(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring6Configuration.class);
UserService userService = applicationContext.getBean("userService", UserService.class);
userService.save();
}
JdbcTemplate
JdbcTemplate是Spring提供的一个JDBC模板,用于操作数据库,是对JDBC的封装,简化jdbc代码,一般集成其他ORM框架框架进行数据库操作,如MyBatis,Hibernate等。
代理模式
使用代理对象代替对原对象的访问,一方面可以隐藏目标对象,另一方面可以在不修改目标对象的情况下增加额外的功能。
Java中的代理:
静态代理:编译时生成,原对象和目标对象实现相同的接口
动态代理:运行时生成
JDK动态代理:使用jdk的proxy类创建代理对象
cglib动态代理:使用cglib的Enhancer类创建代理对象
jdk代理的对象必须实现接口,它是针对接口的代理,cglib所代理的对象不需要实现接口,它是通过继承实现的,所以一般有接口的使用jdk代理,没有接口的使用cglib代理
静态代理和动态代理的区别:静态代理每个接口都需要创建一个代理类,导致类爆炸,并且灵活性很低。动态代理只需要一个代理类,并且灵活性更高。
面向切面编程AOP
面向切面编程可以分离业务逻辑无关的代码作为单独的模块,例如日志,事务等。一方面可以减少重复代码,提供可维护性,另一方面可以使开发者只关注业务逻辑。AOP的原理是动态代理实现的,代理接口使用jdk,代理类使用cjlib。
AOP的核心概念是切面,切面由切入点和通知组成,切入点是我们要增强的方法,通知是我们要植入的代码,包括环绕通知,前置通知,后置通知等等。
使用AOP的方法:
使用AOP有两种方式,第一种方式是基于注解,第二种基于xml。一般使用注解。
1.引入依赖
2.添加配置spring.xml或配置类
@Configuration
@ComponentScan("com.powernode.spring6.service")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class Spring6Configuration {
}
3.定义目标类和目标方法
// 目标类
@Component
public class OrderService {
// 目标方法
public void generate(){
System.out.println("订单已生成!");
}
}
4.定义切面:切入点+通知
// 切面类
@Aspect
@Component
public class MyAspect {
// 切点表达式
@Before("execution(* com.powernode.spring6.service.OrderService.*(..))")
// 这就是植入的代码(通知) @Before代表前置通知
public void advice(){
System.out.println("我是一个通知");
}
}
AOP的使用示例:事务处理,安全日志
@Aspect
@Component
// 事务切面类
public class TransactionAspect {
@Around("execution(* com.powernode.spring6.biz..*(..))")
public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
try {
System.out.println("开启事务");
// 执行目标
proceedingJoinPoint.proceed();
System.out.println("提交事务");
} catch (Throwable e) {
System.out.println("回滚事务");
}
}
}
@Component
@Aspect
public class SecurityAspect {
@Pointcut("execution(* com.powernode.spring6.biz..save*(..))")
public void savePointcut(){}
@Pointcut("execution(* com.powernode.spring6.biz..delete*(..))")
public void deletePointcut(){}
@Pointcut("execution(* com.powernode.spring6.biz..modify*(..))")
public void modifyPointcut(){}
@Before("savePointcut() || deletePointcut() || modifyPointcut()")
public void beforeAdivce(JoinPoint joinpoint){
System.out.println("XXX操作员正在操作"+joinpoint.getSignature().getName()+"方法");
}
}
Spring对事务的支持
什么是事务:一组操作要么全部成功,要么全部失败,保证数据的安全。
事务的四大特性:ACID,原子性,一致性,隔离性,持久性
Spring中对事务的支持:注解方式
配置事务
@Configuration //配置类 代替spring.xml
@ComponentScan("com.powernode.bank") //组件扫描 代替
@EnableTransactionManagement //告诉spring开启事务 代替
public class Spring6Config {
@Bean//定义数据源
public DataSource getDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring6");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
@Bean(name = "jdbcTemplate") //定义jdbctemplate操作数据源
public JdbcTemplate getJdbcTemplate(DataSource dataSource){//spring自动注入参数
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean//定义事务管理器管理数据源
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
使用事务:给类或方法添加@Transactinal注解
@Service("accountService")
@Transactional
public class AccountServiceImpl implements AccountService {
@Resource(name = "accountDao")
private AccountDao accountDao;
@Override
public void transfer(String fromActno, String toActno, double money) {
// 查询账户余额是否充足
Account fromAct = accountDao.selectByActno(fromActno);
if (fromAct.getBalance() < money) {
throw new RuntimeException("账户余额不足");
}
// 余额充足,开始转账
Account toAct = accountDao.selectByActno(toActno);
fromAct.setBalance(fromAct.getBalance() - money);
toAct.setBalance(toAct.getBalance() + money);
int count = accountDao.update(fromAct);
// 模拟异常
String s = null;
s.toString();
count += accountDao.update(toAct);
if (count != 2) {
throw new RuntimeException("转账失败,请联系银行");
}
}
}
测试:
@Test
public void testNoXml(){
//根据配置类创建容器
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Spring6Config.class);
//从容器中获取bean
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
try {
accountService.transfer("act-001", "act-002", 10000);
System.out.println("转账成功");
} catch (Exception e) {
e.printStackTrace();
}
}
事务的属性:
事务的传播行为:
REQUIRE(合并事务)
REQUIRE_NEW(新建事务)
事务的隔离级别:
读未提交
读提交 - 脏读 读取的数据还未提交
可重复读 - 不可重复度 同一事务两次读取的数据不一样
串行化 -幻读 读取的数据和实际表中的数据不一样
事务的超时:
@Transactional(timeout = 10)设置事务的超时时间为10秒。
事务超时是指在一定时间内事务中的所有DML语句还没有执行完,发生回滚。
只读事务:
@Transactional(readOnly = true)
该事务只允许执行select语句,使用spring优化策略,提高效率
设置哪些异常回滚,哪些异常不回滚:
@Transactional(rollbackFor = RuntimeException.class)
@Transactional(noRollbackFor = NullPointerException.class)
Spring整合JUnit
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:spring.xml")
public class SpringJUnit5Test {
@Autowired
private User user;
@Test
public void testUser(){
System.out.println(user.getName());
}
}
Spring继承MyBatis
1.引入依赖
2.配置spring:配置数据源,mybatis
3.编写mapper接口和对象的配置文件
Spring中的八大模式
1.简单工厂模式:IOC,一个工厂根据名称返回对象,不可扩展
2.工厂方法模式:每种对象使用一个工厂创建,可扩展
3.单例模式:双重判断加锁
4.代理模式:AOP
5.装饰器模式:IO流,动态的为已有的对象添加新的功能。
6.观察者模式:一对多的依赖关系,当主题对象状态发生变化时,同时所有观察者对象更新状态。
7.策略模式:将算法的功能和算法的实现分开,实现算法的动态扩展或切换
8.模板方法模式:抽象类中定义方法的执行的模板,子类中重写方法的实现