Spring5 核心概念与代理模式 - 狂神说Java课程笔记

75 阅读3分钟

Spring5 核心概念与代理模式 - 狂神说Java课程笔记

一、Spring概述

1. Spring框架简介

  • 轻量级开源框架​:解决企业应用开发的复杂性
  • 核心特性​:IOC、AOP、事务管理、MVC等
  • 设计理念​:非侵入式设计,代码污染极低

2. Spring优势

  • 方便解耦​:通过IOC容器降低组件耦合度
  • AOP编程支持​:面向切面编程,方便实现日志、事务等功能
  • 声明式事务​:通过配置管理事务,无需硬编码
  • 集成各种优秀框架​:如MyBatis、Hibernate等

二、IOC(控制反转)

1. 核心概念

// 传统方式:主动创建对象
UserService userService = new UserServiceImpl();

// IOC方式:容器管理对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("userService");

2. IOC本质

  • 控制反转​:将对象的创建权交给Spring容器
  • 依赖注入​:容器负责注入对象所需的依赖
  • 好莱坞原则​:"Don't call us, we'll call you"

三、依赖注入(DI)

1. 三种注入方式

<!-- 构造器注入 -->
<bean id="user" class="com.kuang.pojo.User">
    <constructor-arg name="name" value="狂神"/>
</bean>

<!-- Setter注入 -->
<bean id="user" class="com.kuang.pojo.User">
    <property name="name" value="狂神"/>
</bean>

<!-- 接口注入(较少使用) -->

2. 自动装配

  • byName​:根据属性名自动装配
  • byType​:根据类型自动装配
  • 注解方式​:@Autowired、@Resource

四、代理模式

1. 静态代理

实现方式
// 接口
public interface UserService {
    void add();
}

// 真实角色
public class UserServiceImpl implements UserService {
    public void add() {
        System.out.println("添加用户");
    }
}

// 代理角色
public class UserServiceProxy implements UserService {
    private UserService userService;
    
    public UserServiceProxy(UserService userService) {
        this.userService = userService;
    }
    
    public void add() {
        log("before");
        userService.add();
        log("after");
    }
    
    private void log(String msg) {
        System.out.println("执行" + msg + "日志");
    }
}
优缺点
  • 优点​:业务类只需关注业务逻辑
  • 缺点​:接口变化时代理类也需修改;每个真实角色都需要代理类

2. 动态代理

JDK动态代理
public class ProxyInvocationHandler implements InvocationHandler {
    private Object target;
    
    public void setTarget(Object target) {
        this.target = target;
    }
    
    // 生成代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            this
        );
    }
    
    // 处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }
    
    private void log(String msg) {
        System.out.println("执行了" + msg + "方法");
    }
}

// 使用方式
UserService target = new UserServiceImpl();
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(target);
UserService proxy = (UserService) pih.getProxy();
proxy.add();
JDK动态代理特点
  • 基于接口实现
  • 使用Java反射机制
  • 代理类在运行时动态生成

3. CGLIB动态代理

实现方式
public class CglibProxy implements MethodInterceptor {
    private Object target;
    
    public CglibProxy(Object target) {
        this.target = target;
    }
    
    // 创建代理对象
    public Object getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("CGLIB代理开始");
        Object returnValue = method.invoke(target, args);
        System.out.println("CGLIB代理结束");
        return returnValue;
    }
}

// 使用方式
UserService target = new UserServiceImpl();
UserService proxy = (UserService) new CglibProxy(target).getProxyInstance();
proxy.add();
CGLIB特点
  • 基于类实现(不需要接口)
  • 使用字节码处理框架ASM
  • 通过继承方式实现代理

五、三种代理方式对比

特性静态代理JDK动态代理CGLIB动态代理
实现方式手动编写代理类基于接口反射基于继承字节码
编译时需要源码不需要不需要
性能较高反射调用稍慢字节码生成较快
灵活性
适用范围简单场景有接口的场景无接口的场景

六、实际应用场景

  1. Spring AOP​:基于动态代理实现
  2. 事务管理​:通过代理实现声明式事务
  3. 日志记录​:统一的日志处理
  4. 权限控制​:方法级别的权限验证
  5. 性能监控​:方法执行时间统计

学习建议

  1. 理解IOC和DI的设计思想比记住具体实现更重要
  2. 代理模式是理解Spring AOP的基础,需要重点掌握
  3. 动手实践:自己实现简单的IOC容器和代理模式
  4. 结合实际项目理解这些概念的应用场景