【Java】面向小白的Spring Framework注解开发学习笔记

目录

简介

IoC&DI

纯注解实现

[定义 Bean](#定义 Bean)

[Bean 的作用范围和生命周期管理](#Bean 的作用范围和生命周期管理)

依赖注入

[管理第三方 Bean](#管理第三方 Bean)

[为第三方 Bean 注入资源(例如数据库连接池)](#为第三方 Bean 注入资源(例如数据库连接池))

AOP

纯注解实现

工作流程

切面示例

切入点表达式示例

通知类型示例

@Before(前置通知)

@After(后置通知)

@AfterReturning(返回通知)

@AfterThrowing(异常通知)

@Around(环绕通知)


简介

Spring Framework 是一个开源的 Java 企业级应用程序开发框架,它提供了一系列的库和工具,帮助开发人员构建高效、可维护、易扩展的企业级应用程序。Spring 框架是由 Rod Johnson 和 Juergen Hoeller 等人创建的,第一个版本发布于2002年。

Spring Framework 的核心是 IoC(Inversion of Control)容器和 AOP(Aspect Oriented Programming)框架。IoC 容器用于管理 Java 对象(即 Bean),通过依赖注入的方式实现对象之间的解耦。AOP 框架提供了对切面编程的支持,允许开发人员在不修改核心代码的情况下,通过切面技术实现横切关注点的功能,例如事务管理、安全检查等。

IoC&DI

IoC(Inversion of Control,控制反转)和 DI(Dependency Injection,依赖注入)是 Spring Framework 的核心概念之一,它们是通过解耦来提高代码的可维护性和可扩展性。

IoC 意味着对于一个对象的创建和管理不再由该对象自己来决定,而是由外部容器来控制。换句话说,控制权被反转了。在 Spring 中,IoC 通常指的是 Spring IoC 容器,它管理了应用程序中的 Java 对象,并负责调用它们的生命周期方法。

DI 是 IoC 的一种实现方式,它是指将依赖关系从代码中移除,通过容器来注入所需的依赖项。依赖项可以是其他对象、配置属性或者资源等。Spring 中的 DI 通常是通过构造函数注入、Setter 方法注入或者字段注入来实现的。

举例:

// 定义数据访问接口 UserDao,使用 @Repository 注解标记为持久化层组件
@Repository
public interface UserDao {
    void saveUser(User user);
}

// 实现 UserDao 接口,使用 @Repository 注解标记为持久化层组件
@Repository
public class UserDaoImpl implements UserDao {
    @Override
    public void saveUser(User user) {
        // 实现具体的数据库保存逻辑
        System.out.println("Save user: " + user.getName());
    }
}

// 定义服务类 UserService,使用 @Service 注解标记为业务层组件
@Service
public class UserService {
    // 使用 @Autowired 注解自动装配 UserDao 对象
    @Autowired
    private UserDao userDao;

    public void saveUser(User user) {
        userDao.saveUser(user);
    }
}

// 创建 Spring 配置类 AppConfig,用于配置 IoC 容器和依赖注入
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
    // 无需手动定义 bean,因为使用了 @ComponentScan 注解自动扫描并注册组件
}

// 编写测试代码,验证 IoC 和 DI 的效果
public class Main {
    public static void main(String[] args) {
        // 创建 Spring IoC 容器,并加载 AppConfig 配置类
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 从容器中获取 UserService bean
        UserService userService = context.getBean(UserService.class);

        // 创建一个 User 对象
        User user = new User("John Doe");

        // 调用 UserService 的方法保存用户
        userService.saveUser(user);
    }
}

纯注解实现

定义 Bean

@Component // 使用 @Component 注解将该类标记为 Spring 管理的组件
public class UserService {
    // 类的具体实现...
}

Bean 的作用范围和生命周期管理

@Component // 默认为单例作用域,相当于 @Scope("singleton")
public class MySingletonBean {
    // 类的具体实现...
}

@Component
@Scope("prototype") // 指定为原型(多例)作用域
public class MyPrototypeBean {
    // 类的具体实现...
}

@Component
public class MyBeanLifecycle implements InitializingBean, DisposableBean {
    // 在初始化之前执行的方法
    @PostConstruct
    public void init() {
        // 初始化操作...
    }

    // 在销毁之前执行的方法
    @PreDestroy
    public void destroy() {
        // 销毁操作...
    }

    // 实现 InitializingBean 接口的方法
    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化操作...
    }

    // 实现 DisposableBean 接口的方法
    @Override
    public void destroy() throws Exception {
        // 销毁操作...
    }
}

依赖注入

@Component
public class UserService {
    @Autowired // 自动装配依赖对象
    private UserRepository userRepository;
    // 类的具体实现...
}

管理第三方 Bean

@Configuration
public class MyConfig {
    @Bean // 将第三方类库的对象声明为一个 Spring 管理的 bean
    public ThirdPartyService thirdPartyService() {
        return new ThirdPartyService();
    }
}

@Component
public class MyComponent {
    @Autowired
    private ThirdPartyService thirdPartyService;
    // 类的具体实现...
}

为第三方 Bean 注入资源(例如数据库连接池)

@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() {
        // 创建和配置数据源对象...
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        // 使用第三方 bean,并注入资源
        return new JdbcTemplate(dataSource);
    }
}

AOP

Spring 的 AOP(面向切面编程)是一种基于代理机制的编程方式,它可以在不改变原有代码逻辑的情况下,通过动态地将额外的行为织入到程序中。这些额外的行为通常包括日志记录、性能监控、事务管理等与业务功能无关的横切关注点。

在 Spring 中,AOP 可以通过配置或注解来实现。其核心是定义切面(Aspect),切面定义了哪些方法需要被拦截,以及拦截后要执行什么逻辑。而切面具体实现的逻辑则由通知(Advice)来完成。通知可以在目标方法执行前、执行后或者抛出异常时执行,通常采用环绕、前置、后置和异常拦截四种类型。

举例:

@Aspect // 声明该类为切面
@Component
public class LogAspect {
    @Pointcut("execution(* com.example.service.*.*(..))")
    private void serviceMethod() {} // 定义切点,匹配 com.example.service 包下的所有方法

    @Before("serviceMethod()")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[LogAspect] Before method: " + methodName);
    }

    @AfterReturning("serviceMethod()")
    public void logAfterReturning(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("[LogAspect] AfterReturning method: " + methodName);
    }
}

纯注解实现

工作流程

  1. 定义切面(Aspect):通过使用 @Aspect 注解声明一个类为切面,并在该类中定义切入点和通知。

  2. 定义切入点(Pointcut):使用 @Pointcut 注解定义一个切入点表达式,指定哪些方法需要被拦截。

  3. 定义通知(Advice):使用 @Before、@After、@AfterReturning、@AfterThrowing 或 @Around 注解定义通知类型,并编写相应的逻辑。

  4. 将切面和目标对象进行织入:Spring 容器会自动检测并织入切面到匹配的目标对象中。

5.执行增强逻辑:在目标方法执行前、执行后或抛出异常时,触发相应的通知进行增强处理

切面示例

@Aspect
@Component
public class LoggingAspect {
    
    @Pointcut("execution(* com.example.service.*.*(..))")
    private void serviceMethod() {}
    
    @Before("serviceMethod()")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("Before executing method: " + joinPoint.getSignature().getName());
    }
    
    @After("serviceMethod()")
    public void afterAdvice(JoinPoint joinPoint) {
        System.out.println("After executing method: " + joinPoint.getSignature().getName());
    }
}

切入点表达式示例

@Pointcut("execution(* com.example.service.UserService.*(..))")
private void userServiceMethods() {}

@Pointcut("within(com.example.repository.*)")
private void repositoryMethods() {}

通知类型示例

@Before(前置通知)

@Before("execution(* com.example.service.UserService.createUser(String, int))")
public void beforeCreateUserAdvice(JoinPoint joinPoint) {
    Object[] args = joinPoint.getArgs();
    System.out.println("Before creating user... Name: " + args[0] + ", Age: " + args[1]);
}

功能:在执行 com.example.service.UserService.createUser() 方法之前触发该通知,可以用于进行一些预处理操作,例如权限检查、参数校验等。

@After(后置通知)

@After("execution(* com.example.service.UserService.deleteUser(..))")
public void afterDeleteUserAdvice() {
    System.out.println("After deleting user...");
}

功能:在执行 com.example.service.UserService.deleteUser() 方法之后触发该通知,无论方法是否抛出异常都会执行。可以用于进行一些清理操作,例如资源释放、日志记录等。

@AfterReturning(返回通知)

@AfterReturning(pointcut = "execution(* com.example.service.UserService.updateUser(..))", returning = "result")
public void afterUpdateUserAdvice( Object result) {
    System.out.println("After updating user... Result: " + result);
}

功能:在执行 com.example.service.UserService.updateUser() 方法并且方法正常返回后触发该通知。可以用于获取方法的返回值并进行相应的处理,例如记录返回结果、统计信息等。

@AfterThrowing(异常通知)

@AfterThrowing(pointcut = "execution(* com.example.service.UserService.getUser(..))", throwing = "ex")
public void afterThrowingGetUserAdvice(Exception ex) {
    System.out.println("After throwing exception in getUser() method: " + ex.getMessage());
}

功能:在执行 com.example.service.UserService.getUser() 方法抛出异常时触发该通知。可以用于捕获方法抛出的异常并进行相应的处理,例如记录异常信息、进行异常处理等。

@Around(环绕通知)

@Around("execution(* com.example.service.UserService.getAllUsers())")
public Object aroundGetAllUsersAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("Before executing getAllUsers() method...");
    Object result = null;
    try {
        result = joinPoint.proceed();
    } catch (Exception ex) {
        System.out.println("Exception occurred: " + ex.getMessage());
    }
    System.out.println("After executing getAllUsers() method... Result: " + result);
    return result;
}

功能:在执行 com.example.service.UserService.getAllUsers() 方法前后都触发该通知,并且可以控制目标方法的执行。可以用于在方法执行前后进行一些额外的处理,例如性能监控、事务管理等。

相关推荐
神仙别闹35 分钟前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭1 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫1 小时前
泛型(2)
java
超爱吃士力架1 小时前
邀请逻辑
java·linux·后端
南宫生1 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石2 小时前
12/21java基础
java
李小白662 小时前
Spring MVC(上)
java·spring·mvc
sanguine__2 小时前
Web APIs学习 (操作DOM BOM)
学习
GoodStudyAndDayDayUp2 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea
装不满的克莱因瓶2 小时前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb