IOC & DI
1,Inversion Of Control 控制反转(在运行时基于反射发现组件类和注册对象的过程)
(解释说明:1.控制反转:指的是创建对象的控制权由我们程序员反转给了IOC容器。也就是说之 前是我们自己通过new()手动创建对象和组装,现在这些事情都交给了IOC容器 进行管理,我们使用的时候直接去IOC容器里面拿对象就行。
2.为什么要反转:为了降低系统代码之间的耦合度,有利于系统维护和扩展)
创建对象的四种方式:
1.使用new关键字
2.使用Clone /kləʊn/的方法:无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象全表拷贝进去
3.使用反序列化
4.通过反射机制:反射是在运行状态中,对于任意一个类,都能够指定这个类的所有属性和方法;对应任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象的方法的功能成为Java反射机制
发现:运行时让IOC容器发现组件类
1.组件类的包层级不能高于启动类,只能小于等于
2.组件类上需要有IOC注解
具有IOC功能的常用注解
1.@Controller/@RestController
(1) 用于控制层类的发现和注册
2.@Service
(1)用于service 层类的发现和注册
3.@Repository(如果用了MyBatis 框架就不会用到这个注解)(已经不用)
(1)用于Dao层类的发现和注册
4.@Component (已经不用)
(1)用于任意一个普通类的发现和注册
5.@MapperScan
(1)用于发现mapper包,在运行时创建接口的实现类,并注册对象到IOC容器
注册:发现后就会触发注册,注册就是创建对象放入到IOC容器中
2,Dependency Injection /ɪnˈdʒekʃn/ 依赖注入(赋值的过程)
从IOC容器中拿对象,加一个@Resoure注解,就能在IOC容器中找到所需对象,
注入:在运行时,从IOC容器中找到与指针相匹配的对象赋值给指针的过程
(解释说明:)
发现----> 注册 ---> 注入 (这三件事都是在运行时进行)
控制反转,是为了依赖注入
4,为什么要反转?
高内聚低耦合
高内聚:职责,功能相同的放在同一个类中
耦合=依赖(工程依赖工程,类依赖类)
高耦合(直接依赖了具体实现类)
5,解耦合
6, Component 组件(组成工程的元件,指的是类)
Bean/JavaBean 咖啡豆/组成(指的是对象,被IOC容器发现后创建的对象)
7,IOC&DI的实现方式有3种:
1.基于xml 文件实现(已经淘汰)
xml文件写在resources目录中,xml文件可以有多个
2.基于注解实现
3.基于配置类实现
启动类就是一个配置类,或者任意一个带有@Configuration注解的类都可以是一个配置类
发现/注册UserController
发现/注册UserServiceImpl
在UserController中注入UserService
日志管理
Lombok三方库提供的注解
在编译时给字节码中动态生成内容
@Setter
@Getter
@AllArgsConstructor 全参数构造函数
@NoArgsConstructor 是添加一个无参数的构造器
@EqualsAndHashCode
@ToString
@Data=@Setter+@Getter+@EqualsAndHashCode+@ToString
@Slf4j
在编译后的字节码文件中会出现一个私有的静态常量
类型是Logger,指针名为log,这个就是用来打印日志的对象
需要在哪个类中打印,只需要给这个类添加@Slf4j 注解,这个类中就会有一个log指针
private static final Logger log = LoggerFactory.getLogger(UserController.class);
在使用log对象打印日志之前,需要先配置打印日志的规则
1.将日志配置文件放在resources目录中
日志配置文件log.xml可以复用,需要了解里面如何配置日志打印规则
2.在application.properties 中告诉文件在Lombok框架日志配置哪里
设置日志级别
trace /treɪs/ (追踪) < debug(调试) < info(信息) < warn(警告) < error(错误)
设置日志规则
使用log打印日志来代替System.out.println()
写Demo
System.out.println()
写项目
使用log打印
1,log打印的信息更多
日志打印时间,所在线程 所在类 日志信息
2,log可以按照级别打印日志,可以通过级别控制哪些打印,哪些不打印
3,log可以打印到控制台,还可以打印到文件
AOP
面向切面编程(Aspect Oriented Programming),是基于代理模式实现的。(将业务代码和非业务代码进行分离)
通过 try.catch()finally()解决非业务代码和日志打印Log.debug("")解决侵入式代码,这些代码无关紧要,使我们的代码更加简洁,优雅。
通过注解@Aspect /ˈæspekt/ 定义一个切面类,通过 @Pointcut 标注在方法上,用来定义切入点,通过五个增强方式注解来选择想要增强的位置
安装AOP依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
package com.example.springbootshoop.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Slf4j
@Component
@Aspect
public class ControllerAdvice {
@Pointcut("execution(* com.example.springbootshoop.controller.*.*(..))")
public void pointcut(){}
@Before(value = "pointcut()")
public void before(JoinPoint jp){
//拿到目标方法名
String targetMethodName=jp.getSignature().getName();
//拿到目标方法的参数列表
Object[]args=jp.getArgs();
log.info(targetMethodName+"开始执行,参数列表:"+ Arrays.toString(args));
}
@After(value = "pointcut()")
public void after(JoinPoint jp){
String targetMethodName=jp.getSignature().getName();
log.info(targetMethodName+"执行结束");
}
@AfterReturning(value = "pointcut()",returning = "result")
public void afterReturning(JoinPoint jp,Object result){
String targetMethodName=jp.getSignature().getName();
log.info(targetMethodName+"执行结束,返回值"+result);
}
@AfterThrowing(value = "pointcut()",throwing = "e")
public void afterThrowing(JoinPoint jp,Exception e){
String targetMethodName=jp.getSignature().getName();
log.info(targetMethodName+"执行结束,发生异常"+e.getMessage());
}
}