DAY25.2 Java核心基础
Spring两大核心:Ioc和Aop
IOC
Ioc容器:装载bean的容器,自动创建bean
三种方式:
1、基于xml配置:通过在xml里面配置bean,然后通过反射机制创建bean,存入进Ioc容器中
2、基于注解的方式:通过注解标记类,Ioc读取有相关注解的类,然后通过反射创建bean对象存入Ioc容器中
3、基于配置类的方式:写一个java文件来替代xml,通过@Bean注解标记需要创建的对象,通过反射创建存入Ioc容器中
AOP
AOP:Aspect Oriented Programming,面向切面编程
面向对象编程 OOP (Object Oriented Programming):将程序中所有参与模块都抽象成对象,通过对象之间的相互调用关系来完成业务需求。
AOP:指的是把切面抽象为对象,在程序运行的时候动态的将非业务代码(比如打印日志)切入到业务代码中,从而实现代码的解耦合,将非业务代码抽象为一个对象
AOP优点:
- 实现代码的解耦合
- 提高代码的复用性
- 提高代码的可维护性
- 集中式管理横切逻辑
- 提升开发效率
- 业务代码不受非业务代码的影响,逻辑更加清晰
应用场景 | 说明 |
---|---|
日志记录 | 自动打印请求参数、响应、耗时等 |
权限验证 | 判断用户是否有权限执行操作 |
事务管理 | 保证一组数据库操作的原子性 |
性能监控 | 记录方法执行时间、内存等 |
异常处理 | 统一捕获、记录、响应异常信息 |
缓存控制 | 方法调用前先查缓存,结果缓存 |
总结一句话:AOP 本质上是“增强”代码的能力,不修改原代码,也能插入额外逻辑,让系统更模块化、更灵活、更清晰。
案例示例:
创建一个计算的接口
CalService:
public interface CalService {
int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int div(int a, int b);
}
实现类CalServiceImpl
@Component("calService")
public class CalServiceImpl implements CalService{
@Override
public int add(int num1, int num2) {
int result = num1 + num2;
return result;
}
@Override
public int sub(int num1, int num2) {
int result = num1 - num2;
return result;
}
@Override
public int mul(int num1, int num2) {
int result = num1 * num2;
return result;
}
@Override
public int div(int num1, int num2) {
int result = num1 / num2;
return result;
}
}
测试方法
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext("org.nanfengspringboot01.aop");
CalService calService = (CalService) annotationConfigApplicationContext.getBean("calService");
System.out.println(calService.add(4, 2));
System.out.println(calService.sub(4, 2));
System.out.println(calService.mul(4, 2));
System.out.println(calService.div(4, 2));
}
输出:
如果我们需要记录打印日志的话,是不是要更改实现类文件的实现
@Component("calService")
public class CalServiceImpl implements CalService{
@Override
public int add(int num1, int num2) {
System.out.println("执行了加法运算");
int result = num1 + num2;
System.out.println("结果是:" + result);
return result;
}
@Override
public int sub(int num1, int num2) {
System.out.println("执行了减法运算");
int result = num1 - num2;
System.out.println("结果是:" + result);
return result;
}
@Override
public int mul(int num1, int num2) {
System.out.println("执行了乘法运算");
int result = num1 * num2;
System.out.println("结果是:" + result);
return result;
}
@Override
public int div(int num1, int num2) {
System.out.println("执行了除法运算");
int result = num1 / num2;
System.out.println("结果是:" + result);
return result;
}
}
但是这样写的代码耦合程度太高了
咱可以用AOP来实现切面编程,将打印日志作为一个切面类抽象出来
创建切面类CalAop
@Aspect
@Component
public class CalAop {
@Before("execution(public int org.nanfengspringboot01.aop.CalService.*(..))")
public void before(JoinPoint joinPoint) {
System.out.println("Aop切面进入@before");
System.out.println("方法名:" + joinPoint.getSignature().getName());
Object[] args = joinPoint.getArgs();
String string = Arrays.toString(args);
System.out.println("方法参数:"+string);
}
@AfterReturning(value = "execution(public int org.nanfengspringboot01.aop.CalService.*(..))", returning = "result")
public void after(JoinPoint joinPoint,Object result) {
System.out.println("Aop切面进入@AfterReturning");
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName+"方法结果是:"+result);
System.out.println("Aop切面结束");
System.out.println("----------------------------------");
}
}
@Aspect:标记这个类为切面类
@Component:标记这个类需要注入到Ioc容器中
@Before:定义切面的位置,在方法执行之前执行
@AfterReturning/@After:定义切面的位置,在方法执行之后执行
JoinPoint 是 Spring AOP(面向切面编程)中的一个核心接口,它代表了在程序执行过程中可以插入横切关注点(如日志、事务、安全等)的一个具体“连接点”(比如方法调用或异常抛出)。
获取当前连接点的信息
-
可以获取正在被拦截的方法、参数、目标对象等信息。
-
常见用途:记录日志、权限校验、参数处理等。
支持在切面中访问原始方法的上下文
- 例如方法名、参数值、注解等,便于做统一处理。
配合 @Around, @Before, @AfterReturning 等注解使用
- 在定义切面方法时,作为参数传入,用于操作目标方法或获取其执行上下文。
AOP 为什么要使用接口,不直接使用类
AOP 底层实现用的是jdk动态代理,动态创建一个类,创建对象,关于动态代理可以查看我之前的动态代理文章
怎么动态创建类?依据:接口
AOP 是基于 IoC 容器的
使用 IoC 容器创建所有的 bean,再进行整合
有了切面类实现类就不需要打印那么多的日志了
@Component("calService")
public class CalServiceImpl implements CalService{
@Override
public int add(int num1, int num2) {
int result = num1 + num2;
return result;
}
@Override
public int sub(int num1, int num2) {
int result = num1 - num2;
return result;
}
@Override
public int mul(int num1, int num2) {
int result = num1 * num2;
return result;
}
@Override
public int div(int num1, int num2) {
int result = num1 / num2;
return result;
}
}
测试启动类:
@SpringBootApplication
//@EnableAspectJAutoProxy
@MapperScan("org.nanfengspringboot01.mapper")
public class Nanfengspringboot01Application {
public static void main(String[] args) {
ConfigurableApplicationContext ioc = SpringApplication.run(Nanfengspringboot01Application.class, args);
CalService calService = (CalService) ioc.getBean("calService");
calService.add(4,2);
calService.sub(4,2);
calService.mul(4,2);
calService.div(4,2);
}
}
SpringApplication.run(Nanfengspringboot01Application.class, args)的结果就是上下文的ioc容器,可以根据这个获取到所有的bean信息,也可以获取到对应的bean对象
@EnableAspectJAutoProxy注解在新版本是不用加的,springboot会自动整合
输出: