Spring底层机制环境搭建全过程
作者:S-X-S
本文介绍了如何创建和使用Spring框架,包括模块创建、依赖引入、环境搭建、Bean的生命周期管理、AOP编程以及代码托管,通过实际操作和代码示例,详细讲解了Spring的核心概念和功能
Spring底层机制环境搭建
1.模块创建和依赖引入
聚合模块,下面有一个myspring
查看父模块是否管理了子模块
myspring模块引入基本包
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.8</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.3.8</version> </dependency> </dependencies>
2.进行环境搭建
目录概览
UserController.java
package com.sunxiansheng.myspring.component; import org.springframework.stereotype.Component; /** * Description: 就是一个Controller组件 * @Author sun * @Create 2024/8/4 13:53 * @Version 1.0 */ @Component public class UserController { }
UserService.java
package com.sunxiansheng.myspring.component; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * Description: 一个Service组件 * @Author sun * @Create 2024/8/4 13:54 * @Version 1.0 */ @Component public class UserService { /** * 依赖注入UserDao */ @Autowired private UserDao userDao; public void add() { System.out.println("UserService 调用了UserDao的add方法"); userDao.add(); } }
UserDao.java
package com.sunxiansheng.myspring.component; import org.springframework.stereotype.Component; /** * Description: 一个Dao组件 * @Author sun * @Create 2024/8/4 13:53 * @Version 1.0 */ @Component public class UserDao { public void add() { System.out.println("UserDao add..."); } }
AppMain.java
package com.sunxiansheng.myspring; import com.sunxiansheng.myspring.component.UserController; import com.sunxiansheng.myspring.component.UserDao; import com.sunxiansheng.myspring.component.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Description: 启动类 * @Author sun * @Create 2024/8/4 13:59 * @Version 1.0 */ public class AppMain { public static void main(String[] args) { // 从类路径下加载beans.xml配置文件 ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); // 从容器中获取UserController对象,这里获取两次,看是否是同一个对象 UserController userController1 = (UserController) ioc.getBean("userController"); UserController userController2 = (UserController) ioc.getBean("userController"); System.out.println("userController1 == userController2 ? " + (userController1 == userController2)); // 从容器中获取UserService对象 UserService userService = (UserService) ioc.getBean("userService"); System.out.println("userService = " + userService); // 从容器中获取UserDao对象 UserDao userDao = (UserDao) ioc.getBean("userDao"); System.out.println("userDao = " + userDao); } }
beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置自动扫描的包 --> <context:component-scan base-package="com.sunxiansheng.myspring.component"/> </beans>
测试
配置UserController.java为多例的,然后测试
UserService调用add方法,然后测试
引入Bean后置处理器
1.位置
2.MyBeanPostProcessor.java
package com.sunxiansheng.myspring.process; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.stereotype.Component; /** * Description: Bean的后置处理器 * @Author sun * @Create 2024/8/4 14:19 * @Version 1.0 */ @Component // 将这个类加入到容器中 public class MyBeanPostProcessor implements BeanPostProcessor { /** * 在每个Bean的初始化方法之前执行 * @param bean * @param beanName * @return */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { // 这里可以提前对bean进行一些处理 System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean.getClass()); return bean; } /** * 在每个Bean的初始化方法之后执行 * @param bean * @param beanName * @return */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean.getClass()); return bean; } }
3.UserService.java 设置初始化方法
4.beans.xml配置扫描
5.测试
6.注意事项
- bean的后置处理器在初始化方法调用前后执行
- 触发时机为单例的第一次getBean和多例的每次getBean,也就是,每个Bean都会经过Bean的后置处理器处理
引入AOP
1.目录
2.SmartAnimal.java
package com.sunxiansheng.myspring.aop; /** * Description: SmartAnimal * @Author sun * @Create 2024/8/4 14:51 * @Version 1.0 */ public interface SmartAnimal { public float getSum(float a, float b); public float getSub(float a, float b); }
3.SmartDog.java
package com.sunxiansheng.myspring.aop; import org.springframework.stereotype.Component; /** * Description: SmartDog * @Author sun * @Create 2024/8/4 14:51 * @Version 1.0 */ @Component // 交给Spring容器管理 public class SmartDog implements SmartAnimal { @Override public float getSum(float a, float b) { System.out.println("SmartDog...getSum...res=" + (a + b)); return a + b; } @Override public float getSub(float a, float b) { System.out.println("SmartDog...getSub...res=" + (a - b)); return a - b; } }
4.SmartAnimalAspect.java
package com.sunxiansheng.myspring.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import java.util.Arrays; /** * Description: 切面类 * @Author sun * @Create 2024/8/4 14:53 * @Version 1.0 */ @Component // 交给Spring容器管理 @Aspect // 标注这是一个切面类 public class SmartAnimalAspect { /** * @param joinPoint 保存了要切入的方法的信息 * @Before 前置通知 * execution(。。。) 切入表达式,表明要切入的方法,格式:格式:访问修饰符+返回类型 全类名 方法名(参数类型) */ @Before(value = "execution(public float com.sunxiansheng.myspring.aop.SmartDog.getSub(float, float))") public void before(JoinPoint joinPoint) { // 获取方法签名 Signature signature = joinPoint.getSignature(); System.out.println("方法执行开始-日志-方法名-" + signature.getName() + "-参数" + Arrays.asList(joinPoint.getArgs())); // 还可以获取目标对象,这样就可以反射进行任何操作了 SmartDog target = (SmartDog) joinPoint.getTarget(); System.out.println("目标对象-" + target.getClass()); } /** * @param joinPoint 保存了要切入的方法的信息 * @AfterReturning 返回通知 */ @AfterReturning(value = "execution(public float com.sunxiansheng.myspring.aop.SmartDog.getSub(float, float))") public void afterReturning(JoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); System.out.println("方法执行正常结束-日志-方法名-" + signature.getName()); } /** * @param joinPoint * @AfterThrowing 异常通知 */ @AfterThrowing(value = "execution(public float com.sunxiansheng.myspring.aop.SmartDog.getSub(float, float))") public void throwing(JoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); System.out.println("方法出现异常-日志-方法名-" + signature.getName()); } /** * @param joinPoint * @After 后置通知 */ @After(value = "execution(public float com.sunxiansheng.myspring.aop.SmartDog.getSub(float, float))") public void after(JoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); System.out.println("方法最终执行完毕-日志-方法名-" + signature.getName()); } /** * 环绕通知 * @param joinPoint * @return * @throws Throwable */ @Around("execution(public float com.sunxiansheng.myspring.aop.SmartDog.getSub(float, float))") public Object logMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); // 获取方法信息 String methodName = signature.getMethod().getName(); String className = signature.getDeclaringType().getSimpleName(); System.out.println("环绕通知 method " + className + "." + methodName); // 获取目标对象 Object targetObject = joinPoint.getTarget(); // 环绕通知获取目标对象 System.out.println("环绕通知获取目标对象:" + targetObject); try { // 前置通知:环绕通知获取参数 System.out.println("环绕通知获取参数:" + Arrays.asList(joinPoint.getArgs())); Object result = joinPoint.proceed(); // 执行目标方法 // 返回通知:环绕通知获取结果 System.out.println("环绕通知获取结果:" + result); return result; } catch (Exception e) { // 异常通知 throw e; } finally { // 最终通知 System.out.println("环绕通知 method " + className + "." + methodName); } } }
5.beans.xml开启aop注解并扫描aop包
6.AppMain.java 测试AOP
6.简单分析AOP和后置处理器的关系
3.抛出问题
- 1.bean是怎么注入容器的?
- 2.为什么加了@Autowired就能被依赖注入?
- 3.单例多例是怎么实现的?
- 4.Bean的后置处理器是怎么实现的?
- 5.原生Spring的AOP是如何实现的?
4.将代码放到远程仓库
- VCS -》 share
- 查看仓库
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。