Spring
spring是由interface21框架为基础经过重新设计,并不断丰富其内涵在2004年3月24日发布了1.0版本。
spring的创作理念就在于使现有的技术更加容易使用
优点
Spring是一个开源的免费框架(容器)
Spring是一个轻量级非入侵式的框架
Spring的核心技术控制反转(IOC)和面向切面编程(AOP)
支持事务的处理,支持框架的整合。
总结:Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
Spring的组成
Core Container(核心容器)
功能:IoC(控制反转)和 DI(依赖注入)实现,管理 Bean 的生命周期。
核心类:
ApplicationContext
、BeanFactory
AOP(面向切面编程)
功能:通过动态代理实现日志、事务等横切逻辑。
注解:
@Aspect
、@Transactional
Data Access(数据访问)
功能:简化 JDBC(
JdbcTemplate
)、集成 ORM(Hibernate/JPA)。事务管理:声明式事务(
@Transactional
)
Web MVC
功能:基于 Servlet 的 MVC 框架,支持 REST。
核心类:
DispatcherServlet
、@Controller
Context(上下文)
功能:扩展
ApplicationContext
,提供国际化、事件机制等。
WebFlux(响应式 Web)
功能:非阻塞响应式编程(基于 Reactor),替代传统 Web MVC。
Testing(测试)
功能:集成 JUnit,支持 Mock 测试(
@SpringBootTest
)。
IOC和AOP
Spring Ioc:控制反转的意思,它指的是一种思想,早些时候我们需要通过new关键字来创造对象,这就存在了一个弊端,当用户需要其它功能的时候,就会出现问题,我们就需要实时的根据需求进行修改,当我们通过IOC容器来帮我们进行实例化对象的时候,就大大的降低了对象之间的耦合度。依赖注入DI就是实现这个技术的一种方式。
AOP(面向切面编程) 的核心思想是:将与业务无关的通用功能(如日志、事务、权限)从业务代码中剥离,以切面(Aspect)的形式统一管理,避免代码重复和耦合。Spring AOP 的代理实现分为 JDK 动态代理 和 CGLIB 代理,具体选择取决于目标对象是否实现接口。
当我们使用Spring AOP的时候:
1.先添加依赖:
<!-- Maven 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.定义切面类
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
// 定义切入点:拦截 service 包下所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}
// 前置通知:方法执行前调用
@Before("serviceMethods()")
public void beforeAdvice() {
System.out.println("【前置通知】准备执行方法...");
}
// 后置通知:方法正常返回后调用
@AfterReturning(pointcut = "serviceMethods()", returning = "result")
public void afterReturningAdvice(Object result) {
System.out.println("【后置通知】方法执行成功,返回值:" + result);
}
// 异常通知:方法抛出异常时调用
@AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")
public void afterThrowingAdvice(Exception ex) {
System.out.println("【异常通知】方法执行异常:" + ex.getMessage());
}
// 环绕通知:控制方法整个执行流程
@Around("serviceMethods()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("【环绕通知】方法开始执行...");
Object result = pjp.proceed(); // 执行目标方法
System.out.println("【环绕通知】方法执行结束");
return result;
}
}
3.切入点表达式
Spring AOP使用AspectJ切入点表达式语言定义切入点:
execution([修饰符] 返回类型 [类名].方法名(参数) [异常])
*
代表任意..
代表任意参数或包路径示例:
execution(public * *(..))
- 所有public方法execution(* set*(..))
- 所有以set开头的方法execution(* com.xyz.service.*.*(..))
- service包下所有类的所有方法execution(* com.xyz.service..*.*(..))
- service包及其子包下所有类的所有方法
4.通知执行顺序
环绕通知的前半部分(@Around)
前置通知(@Before)
目标方法执行
后置通知(@AfterReturning)或异常通知(@AfterThrowing)
最终通知(@After)
环绕通知的后半部分(@Around)
可以通过@Order
注解指定切面执行顺序:
@Aspect
@Component
@Order(1) // 数字越小优先级越高
public class LoggingAspect {
// ...
}
Spring AOP的高级特性
1.获取方法的信息
在通知方法中可以通过JoinPoint
或ProceedingJoinPoint
获取方法信息:
@Before("serviceLayer()")
public void logBefore(JoinPoint joinPoint) {
// 获取方法签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 获取方法参数名和值
String[] paramNames = signature.getParameterNames();
Object[] paramValues = joinPoint.getArgs();
// 获取目标类
Object target = joinPoint.getTarget();
Class<?> targetClass = target.getClass();
}
2.处理通知中的异常
在环绕通知当中可以捕获并处理异常
@Around("serviceLayer()")
public Object handleException(ProceedingJoinPoint joinPoint) {
try {
return joinPoint.proceed();
} catch (BusinessException ex) {
// 处理业务异常
return fallbackResult();
} catch (Throwable ex) {
// 处理其他异常
throw new RuntimeException("系统异常", ex);
}
}
Spring AOP 的代理实现分为 JDK 动态代理 和 CGLIB 代理,具体选择取决于目标对象是否实现接口。
JDK动态代理
需要目标至少实现一个接口,实现原理:JDK动态代理通过反射在运行时动态生成实现指定接口的代理类,将方法调用转发到InvocationHandler处理,在调用真实方法前后可插入自定义逻辑。
我们进行示例:
1.定义业务接口和实现
public interface OrderService {
void createOrder(String orderId);
void cancelOrder(String orderId);
}
public class OrderServiceImpl implements OrderService {
@Override
public void createOrder(String orderId) {
System.out.println("创建订单: " + orderId);
}
@Override
public void cancelOrder(String orderId) {
System.out.println("取消订单: " + orderId);
}
}
2.实现InvocationHandler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class OrderServiceHandler implements InvocationHandler {
private final Object target; // 目标对象
public OrderServiceHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置处理
System.out.println("[日志] 开始执行 " + method.getName() + " 方法");
System.out.println("[参数] " + (args != null ? Arrays.toString(args) : "无"));
// 调用目标方法
Object result = method.invoke(target, args);
// 后置处理
System.out.println("[日志] " + method.getName() + " 方法执行完成");
return result;
}
}
3.创建并使用
import java.lang.reflect.Proxy;
public class JdkProxyDemo {
public static void main(String[] args) {
// 1. 创建目标对象
OrderService target = new OrderServiceImpl();
// 2. 创建调用处理器
OrderServiceHandler handler = new OrderServiceHandler(target);
// 3. 创建代理对象
OrderService proxy = (OrderService) Proxy.newProxyInstance(
OrderService.class.getClassLoader(), // 类加载器
new Class[]{OrderService.class}, // 代理接口数组
handler // 调用处理器
);
// 4. 使用代理对象
proxy.createOrder("ORD123456");
System.out.println("----------------");
proxy.cancelOrder("ORD123456");
}
}
执行结果
[日志] 开始执行 createOrder 方法
[参数] [ORD123456]
创建订单: ORD123456
[日志] createOrder 方法执行完成
----------------
[日志] 开始执行 cancelOrder 方法
[参数] [ORD123456]
取消订单: ORD123456
[日志] cancelOrder 方法执行完成
CGLIB动态代理
CGLIB动态代理通过继承目标类生成子类,重写方法实现代理,无需接口即可拦截方法调用(无法代理final类/方法)。
示例:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibDemo {
// 目标类(无需接口)
static class UserService {
public void saveUser(String name) {
System.out.println("保存用户: " + name);
}
}
public static void main(String[] args) {
// 1. 创建 Enhancer
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class); // 设置父类(目标类)
// 2. 设置回调(拦截逻辑)
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
System.out.println("[CGLIB] 方法调用前: " + method.getName());
Object result = proxy.invokeSuper(obj, args); // 调用父类方法
System.out.println("[CGLIB] 方法调用后");
return result;
});
// 3. 生成代理对象
UserService proxy = (UserService) enhancer.create();
// 4. 调用代理方法
proxy.saveUser("张三");
}
}
Spring AOP 是高层抽象,底层默认通过 JDK动态代理(基于接口)或 CGLIB(基于子类)实现动态代理