找回密码
 立即注册
首页 业界区 业界 Spring篇知识点(1)

Spring篇知识点(1)

峰埋姚 2025-10-1 19:13:32
 
一、Spring框架的特性


  •  IOC和DI支持:Spring 的核⼼就是⼀个⼤的⼯⼚容器,可以维护所有对象的创建和依赖关系,Spring ⼯⼚⽤于⽣成Bean,并且管理 Bean 的⽣命周期,实现⾼内聚低耦合的设计理念。
  • AOP编程支持:方便实现对程序进行权限拦截、运行监控等切面功能
  • 声明式事务支持:加@Transactional注解,方法执行时自动开启/提交/回滚事务。
  • 快捷测试支持:Spring 提供了 Spring TestContext Framework,方便做单元测试/集成测试。可以直接在测试里加载 Spring 容器,注入 Bean。
  • 快速集成功能:指的是 Spring Boot 提供的一套 Starter 机制。通过一个依赖 + 配置文件,就能自动接入常见的第三方框架,省去大量手写配置。
  • 复杂API模板封装:链式
二、Spring框架由哪些部分组成


  •  Spring Container(核心容器)

    • Spring Core:提供 IoC、依赖注入(DI)的底层功能。
    • Spring Beans:BeanFactory、ApplicationContext,负责 Bean 的生命周期和管理。
    • Spring Context:更高级的 IoC 容器,支持国际化、事件传播、资源加载
    • Spring Expression Language (SpEL):支持在配置文件和注解里写表达式,比如 #{user.age}、${db.url}。

  • AOP:@Transactional、AOP 日志切面。
  • Data Access/Integration:JdbcTemplate 简化原始 JDBC API。整合 Hibernate、MyBatis、JPA 等。提供声明式事务和编程式事务。
  • Spring Web:Spring MVC,最常用的 Web 框架,基于 Servlet,支持 RESTful API。
  • Test:

    • 提供对 JUnit、TestNG 的集成。
    • 提供 Spring TestContext Framework,可以在测试中直接注入 Bean。
    • 支持 MockMvc 模拟 Web 请求测试。

三、Spring中常用注解

1. Web

① @ Controller
  @RestController = @Controller + @ResponseBody
  Java里的返回值 = 逻辑视图名,如“home”,再交给模板引擎渲染成完整的HTML页面(如 templates/home.html),最后返回给浏览器。
  若你用@Controller,加了@ResponseBody,返回值就直接写到响应体,不会再走试图解析器,跟@RestController 的作用一样。
② RequestMapping
  这是请求映射注解,用来把HTTP请求映射到控制器方法或类。包括类级别和方法级别。
  1. @Controller<br>// 类级别
  2. @RequestMapping("/users")
  3. public class UserController {
  4.   // 方法级别
  5.     @RequestMapping("/list")
  6.     public String listUsers() {
  7.         return "userList"; // 返回页面
  8.     }
  9. }<br>// 请求/users/list 会映射到 listUsers()。<br data-start="484" data-end="487">// 类上的 @RequestMapping 作为 <strong data-start="512" data-end="518">前缀</strong>,方法上的作为 <strong data-start="526" data-end="532">后缀</strong>。
复制代码
  1) 指定请求方法:
1.png

   2) 指定参数条件
  1. // 只有带 ?role=admin 的请求才会匹配。
  2. @RequestMapping(value="/search", params="role=admin")
  3. public String searchAdmins() { ... }
复制代码
  3) 指定请求头
  1. @RequestMapping(value="/json", headers="Content-Type=application/json")
  2. public String handleJson() { ... }
复制代码
③ ReponseBody
  把方法返回值直接写到 HTTP 响应体里(JSON、字符串等),而不是解析为视图。
④ @RequestBody
  把 请求体 JSON/XML 自动反序列化为 Java 对象。
  1. // 请求
  2. {
  3.   "name": "Alice",
  4.   "password": "123456"
  5. }
  6. @PostMapping("/login")
  7. public String login(@RequestBody User user) {
  8.     return "用户 " + user.getName() + " 登录成功";
  9. }
复制代码
⑤ @PathVariable
  把 URL 路径参数绑定到方法参数。
  1. @GetMapping("/users/{id}")
  2. public String getUserById(@PathVariable("id") int userId) {
  3.     return "查询用户ID: " + userId;
  4. }
复制代码
2、容器

① Component
  通用的组件标识,告诉Spring这是一个需要被容器管理的类。Spring启动时会扫描并注册到容器里。(自己写的业务类)
② Service
  业务逻辑层组件,语义化的@Component,功能和它一样,区别在于职责标识。
③ Repository
  数据访问层组件(DAO),通常操作数据库。它会额外提供 数据访问异常转换 功能。
  1. @Repository
  2. public class UserDao {
  3.     public void save(User user) {
  4.         // JDBC 操作
  5.         throw new SQLException("主键重复");
  6.     }
  7. }
复制代码
  Spring 会拦截,把 SQLException 转换为 DuplicateKeyException(继承自 DataAccessException)。
  你在上层 service 里就统一 catch DataAccessException 就行了。
④ Autowired
  自动注入依赖(按照类型注入)。
⑤ Qualifier
  当一个接口有多个实现类时,用来指定具体注入哪一个。
  1. public interface Payment {
  2.     void pay();
  3. }
  4. @Component("aliPay")
  5. class AliPay implements Payment {
  6.     public void pay() { System.out.println("支付宝支付"); }
  7. }
  8. @Component("wechatPay")
  9. class WechatPay implements Payment {
  10.     public void pay() { System.out.println("微信支付"); }
  11. }
  12. @Service
  13. class PayService {
  14.     @Autowired
  15.     @Qualifier("aliPay")  // 指定用支付宝
  16.     private Payment payment;
  17.     public void doPay() {
  18.         payment.pay();
  19.     }
  20. }
复制代码
⑥ Configuration
  1. <bean id="appName" >
  2.     <constructor-arg value="MySpringApp"/>
  3. </bean>
  4. @Component
  5. public class AppConfig {
  6.     @Bean
  7.     public String appName() {
  8.         return "MySpringApp";
  9.     }
  10. }
复制代码
  若是第三方类,不是你自己的写的,需要往容器里加。如果用@Component也能运行,但Spring不会做CGLIB代理,每次调用appName()都会执行一次方法,可能得到多个不同的实例。但@Configuration会被CGLIB代码,保证@Bean方法返回的都是单例Bean。——如果很多第三方类(数据库连接池、消息队列客户端等)都很重,如果每次都重新new,会造成资源浪费、状态丢失(有些对象需要维护上下文、缓存)。所以Spting希望通过容器来统一管理这些第三方对象,保证它们是单例且可控。
⑦ Value
  注入外部配置(application.properties / yml)里的值。
  1. @Service
  2. public class ConfigService {
  3.     @Value("${server.port}")
  4.     private int port;
  5.     public void printPort() {
  6.         System.out.println("服务端口: " + port);
  7.     }
  8. }
复制代码
⑧ Bean
  告诉 Spring 容器要手动注册一个 bean(方法的返回值会交给 Spring 管理)。
⑨ Scope
作用:定义 Bean 的作用域。常见的有:

  • singleton(默认,单例)
  • prototype(每次 new 一个新的)
  • request(一次 HTTP 请求一个实例)
  • session(一次会话一个实例)
  1. @Component
  2. @Scope("prototype")
  3. public class PrototypeBean {
  4.     public PrototypeBean() {
  5.         System.out.println("新建 PrototypeBean 实例");
  6.     }
  7. }
复制代码
3、AOP

(1) @Aspect:声明是一个切面类,切面里定义的就是要织入的横切逻辑(入日志、事务、权限等)
① PointCut:定义一个切点,也就是拦截规则。execution(访问修饰符 返回类型 包名.类名.方法名(参数))
② @After:在目标方法执行 之后 执行(无论是否抛异常)。
③ @Before:在目标方法执行 之前 执行。
④ @Around:环绕增强,可以在方法前后都插入逻辑,还能决定方法是否执行。
  1. @Aspect
  2. @Component
  3. public class LogAspect {
  4.     // 定义切点:匹配 service 包下所有方法
  5.     @Pointcut("execution(* com.example.service.*.*(..))")
  6.     public void serviceMethods() {}
  7.     @Before("serviceMethods()")
  8.     public void logBefore(JoinPoint joinPoint) {
  9.         System.out.println("前置日志: " + joinPoint.getSignature().getName());
  10.     }
  11.     @After("serviceMethods()")
  12.     public void logAfter(JoinPoint joinPoint) {
  13.         System.out.println("后置日志: " + joinPoint.getSignature().getName());
  14.     }
  15.     @Around("serviceMethods()")
  16.     public Object logAround(ProceedingJoinPoint pjp) throws Throwable {
  17.         System.out.println("环绕前: " + pjp.getSignature().getName());
  18.         Object result = pjp.proceed();
  19.         System.out.println("环绕后: " + pjp.getSignature().getName());
  20.         return result;
  21.     }
  22. }
复制代码
4、事务

@Transactinal
  1. // 1.基本用法<br>@Service
  2. public class UserService {
  3.     @Autowired
  4.     private UserRepository userRepository;
  5.     @Transactional
  6.     public void createUser(String name) {
  7.         userRepository.save(new User(name));
  8.         // 模拟异常<br>     //如果 name = "error",抛异常,事务会回滚,用户不会被插入数据库。
  9.         if ("error".equals(name)) {
  10.             throw new RuntimeException("模拟异常");
  11.         }
  12.     }
  13. }
复制代码
  1. //1.作用在类上
  2. @Service
  3. @Transactional
  4. public class OrderService {
  5.     public void createOrder() {
  6.         // 所有 public 方法自动开启事务
  7.     }
  8. }
  9. //2. 指定异常回滚
  10. @Transactional(rollbackFor = Exception.class)
  11. public void updateData() {
  12.     // 即使抛 IOException 也会回滚
  13. }
  14. @Transactional(noRollbackFor = ArithmeticException.class)
  15. public void calc() {
  16.     int x = 1 / 0; // 抛异常,但不回滚
  17. }
  18. //3.事务的隔离级别
  19. //READ_COMMITTED——读可提交
  20. // REPEATABLE_READ——可重复读(MySQL 默认)
  21. // SERIALIZABLE——串行化
  22. @Transactional(isolation = Isolation.SERIALIZABLE)
  23. public void serializableTx() {
  24.     // 严格的事务隔离
  25. }
复制代码
事务并发可能出现的问题:

  • 脏读:事务A读到了事务B还没提交的数据
  • 不可重复读:事务A在两次查询中,事务B修改了数据,导致结果不一致
  • 幻读:事务A查询某个范围的数据,事务B插入了新数据,事务A再查时发现多了行
SQL标准的四种隔离级别:

  • READ UNCOMMITTED(读未提交):事务可以读到其他事务未提交的数据。会导致脏读、不可重复读、幻读
  • READ COMMITTED(读已提交):只能读到已提交的数据。解决了脏读,可能出现后面两个。这是Oracle默认隔离级别
  • EPEATABLE READ(可重复读):在同一事务内,多次读取同一行结果一致。解决了前两个,可能出现幻读。(mysql innoDB的默认隔离级别)
  • SERIALIZABLE(串行化):所有事务串行执行,像排队一样。解决了三个。但性能最差。 (对数据一致性要求极高的情况,如银行转账)
四、Spring中用了哪些设计模式?

1. 工厂模式
  传统方式是自己new对象,但在Spring是一个大工厂,用来生产和管理对象Bean。
  1. //手动写代码拿bean
  2. public class Test {
  3.     public static void main(String[] args) {
  4.         ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
  5.         OrderService orderService = ctx.getBean(OrderService.class);
  6.         orderService.placeOrder();
  7.     }
  8. }
  9. //自动(推荐),容器在启动时完成依赖注入,相当于Spring自动帮你调用了getBean()
  10. @Service
  11. public class OrderService {
  12.     @Autowired
  13.     private UserService userService;
  14.     public void placeOrder() {
  15.         userService.sayHello();
  16.     }
  17. }
复制代码
2. 代理模式
  Spring AOP的核心是动态代理(JDK Proxy或CGLIB)。若没有代理的话,一个方法没有事务控制,也没有额外逻辑。引入代理的思想,就是在不改变目标类的前提下,为它“加功能”。如下所示,OrderService是目标类,Spring在启动时会生成一个代理类。于是,你注入的其实是代理对象,而不是自己new 的OrderService。
  1. @Service
  2. public class OrderService {
  3.     @Transactional
  4.     public void createOrder() {
  5.         System.out.println("创建订单");
  6.     }
  7. }
  8. // 伪代码演示:
  9. class OrderServiceProxy extends OrderService {
  10.     @Override
  11.     public void createOrder() {
  12.         // 事务开始
  13.         try {
  14.             super.createOrder(); // 调用目标方法
  15.             // 提交事务
  16.         } catch (Exception e) {
  17.             // 回滚事务
  18.         }
  19.     }
  20. }<br>// 执行时的实际流程:<br>// 1. 调用的是代理对象的createOrder()<br>// 2. 代理对象会:开启事务-->执行真正的createOrder()-->成功则提交事务-->失败则回滚事务
复制代码
JDK Proxy vs CGLIB,Spring使用这两种动态代理机制:
1、JDK动态代理:JDK自带的Proxy,只能给接口生成代理类。代理类实现了统一接口,然后把调用转发给目标对象。
// 接口
public interface UserService {
      void sayHello();
}
// 实现类
public class UserServiceImpl implements UserService {
      public void sayHello() {
            System.out.println("Hello User");
      }
}
2、CGLIB动态代理:用字节码技术,直接生成目标类的子类,然后覆盖方法。
class UserService$$Proxy extends UserService { // 继承目标类
      @Override
      public void sayHello() {
               // 代理逻辑
            System.out.println("事务开始");
            super.sayHello(); // 调用父类方法
            System.out.println("事务提交");
      }
}
3、 Spring为什么要区分

  • 如果目标类有接口,Spring 默认走 JDK Proxy,因为更轻量、JDK 自带。
  • 如果目标类没有接口,Spring 自动退回到 CGLIB,保证依然能代理。
3. 单例模式
  Spring Bena默认作用域是单例,容器中一个Bean只有一个实例。也就是如果反复注入一个类,得到的是一个对象。
4. 模板模式
  Spring提供了很多模板类,比如 JdbcTemplate、RestTemplate,把公共流程固定下来,query() 固定了 获取连接 → 执行 SQL → 释放资源 的流程,具体怎么封装结果集由你提供。
  1. JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
  2. List<User> users = jdbcTemplate.query("SELECT * FROM user",
  3.         (rs, rowNum) -> new User(rs.getInt("id"), rs.getString("name")));
复制代码
5. 观察者模式
  1. // 自定义事件
  2. public class UserRegisterEvent extends ApplicationEvent {<br>  // 说明这是一个可以被Spring容器识别、发布和监听的事件类型
  3.     public UserRegisterEvent(Object source) { super(source); }
  4. }
  5. // 事件发布
  6. @Component
  7. public class UserService {
  8.     @Autowired
  9.     private ApplicationEventPublisher publisher;
  10.     public void registerUser() {
  11.         System.out.println("用户注册");
  12.         publisher.publishEvent(new UserRegisterEvent(this));
  13.     }
  14. }
  15. // 事件监听
  16. @Component
  17. public class EmailListener {
  18.     @EventListener
  19.     public void onUserRegister(UserRegisterEvent event) {
  20.         System.out.println("发送注册成功邮件");
  21.     }
  22. }
复制代码
  这里会先自定义事件类,继承自ApplicationEvent。然后用户服务类注入ApplicationEventPublisher(这是Spring提供的事件发布器),当执行了registerUser方法时,会调用publisher.publishEvent(new UserRegisterEvent(this)),发布一个用户注册事件。ApplicationEventPublisher 接收到事件后,会把事件分发给所有感兴趣的监听器。当外部如果userService.registerUser()时,Spring会自动调用这个监听的方法。
6. 适配器模式
  适配器模式是把一个接口转换成另一个接口,让原本不兼容的类可以一起工作(类比插头转换器)。如果在Spring MVC 场景里,DispatcherServlet收到请求后会找到对应的 Controller,执行 Controller,返回结果。但Controller有很多种写法,如常见的 @Controller + @RequestMapping、实现了HttpRequestHandler 接口的 Controller或更老式的Controller。这时就引入一个HandlerAdapter。

  • 每种 Controller 对应一个 HandlerAdapter。
  • DispatcherServlet 不直接调用 Controller,而是通过 HandlerAdapter 来执行。
  • 这样 DispatcherServlet 就只管“调适配器”,不用关心 Controller 的具体类型。
 
7. 策略模式
   Spring中有一个Resource接口,它的不同实现类,会根据不同的策略去访问资源。
IOC

5、说一说什么是IOC?什么是DI?

   Java是一个面向对象的语言,我们在代码里就是创建对象和对象的依赖。IOC是控制反转的思想,就是由容器来负责控制对象的生命周期和对象间的关系。引入IOC之后控制对象生命周期的不再是引用它的对象,而是容器。
  DI(依赖注入),指的是容器在实例化对象的时候把它依赖的类注入给它。所以我理解的是IOC是思想,DI是实现。
   那使用IOC的最主要的目的就是为了让对象间不再过度耦合,写代码的时候可以专注于业务,而不是复杂的对象的生命周期的管理和依赖。
6、简单说一下Spring IOC 的实现机制

   Spring启动时会读取配置文件/注解,生成一堆BeanDefinition 对象,可能包含beanName、beanClass、scope、lazy-init(懒加载,意思是容器启动的时候先不实例化,等到要用的时候再实例化?),这个BeanDefinition 本身 不是 UserService 实例,而是 UserService 的“说明书”。
  1. @Component
  2. public class UserService { }
  3. public static void main(String[] args) {
  4.     ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
  5.     // 容器启动时,UserService 单例 Bean 已经被 getBean() 过了
  6. }
复制代码
  如果是设置了@Lazy或prototype作用域,容器启动时不会创建,只有在你第一次显式调用getBean时才会触发创建。在业务代码里,一般会通过@Autowired(后台自动调用getBean())来注入对象,即若Spring在实例化一个Bean时,若它依赖了其他Bean,容器会自动调用getBean(“userDao”)来拿到依赖的对象。
  若是第一次getBean,先查singletonObjects,若没有的话会doCreateBean()进行实例化对象,然后通过反射填充属性,放入singletonObjects。若是第二次getBean,就直接从singletonObjects HashMap取对象。
  1. @Service
  2. public class <strong>UserService</strong> {
  3.     @Autowired
  4.     private UserDao userDao;<br>   private String name;
复制代码
  1.     public void <strong>doSomething</strong>() {
  2.         userDao.query();
  3.     }
  4. }
  5. @Repository
  6. public class UserDao {
  7.     public void query() {
  8.         System.out.println("UserDao 查询数据库...");
  9.     }
  10. }<br>//从上面可以看出,UserService依赖UserDao,<br>//那么后台是怎么通过@Autowired注解就把这个类注入进来的呢?
复制代码
  1. // ====================== 容器启动 ======================
  2. // 1. 扫描到 UserService、UserDao
  3. BeanDefinition userServiceDef = new BeanDefinition(UserService.class);
  4. BeanDefinition userDaoDef = new BeanDefinition(UserDao.class);
  5. // 放到 beanDefinitionMap
  6. beanDefinitionMap.put("userService", userServiceDef);
  7. beanDefinitionMap.put("userDao", userDaoDef);
  8. // ====================== 第一次 getBean(UserService) ======================
  9. public Object <strong>getBean</strong>(String name) {
  10.     // 2. 查缓存 → 没有
  11.     Object bean = singletonObjects.get(name);
  12.     if (bean != null) return bean;
  13.     // 3. 没有 → 创建 Bean
  14.     return doCreateBean(beanDefinitionMap.get(name));
  15. }
  16. private Object <strong>doCreateBean</strong>(BeanDefinition def) {
  17.     // 4. 用反射创建对象
  18.     Object bean = def.getBeanClass().newInstance();
  19.     // 相当于 new UserService()
  20.     // 5. 填充属性(依赖注入)<br>  // 取出UserService中的字段对象:userDao和name
  21.     for (Field field : def.getBeanClass().getDeclaredFields()) {<br>    // 只对有autowired注解的字段处理
  22.         if (field.isAnnotationPresent(<strong>Autowired</strong>.class)) {
  23.             // 找到依赖 UserDao
  24.             Object dependency = getBean("userDao"); // 递归调用 getBean
  25.        // 暴力破解Java的访问检查(private),让反射能操作私有字段
  26.             field.setAccessible(true);<br>       // 相当于userService.userDao = userDao;
  27.             field.set(bean, dependency);
  28.         }
  29.     }
  30.     // 6. 放进单例池
  31.     singletonObjects.put(def.getBeanName(), bean);
  32.     return bean;
  33. }
  34. //最终效果:业务代码
  35. userService.doSomething();
  36. //实际运行
  37. // userService 内部的 userDao 已经被 Spring 注入好了
  38. userService.userDao.query();
  39. //输出
  40. UserDao 查询数据库...
复制代码
7、说说BeanFactory和ApplicantContext

   BeanFacotory时Spring最基础的 IOC 容器,负责创建和管理Bean。它的做法跟上面讲的做法是一样的。特点是启动时只保存Bean的定义信息,只有当第一次getBean的时候,采用反射去创建对象,创建好后放到单例池,下次再用就直接拿。
  ApplicantContext是BeanFactory的子接口,功能更完整,是企业级容器。在启动时就会把所有单例Bean创建好(除非标了@Lazy),除了IOC,还提供很多高级功能,如国际化、事件机制,与AOP、事务等框架集成。
8、你知道Spring容器启动阶段会干什么吗

   ① 加载配置
  可能是XML、注解等,Spring会读取这些配置,把Bean的信息(类名、作用域、以来等)保存成BeanDefinition。放在一个beanDefinitionMap里。
  ② 注册beanDefinition
  把所有解析到的beanDefinition放到容器的注册表(DefaultListableBeanFactory)里,这一步只保存“描述信息”,还没真正创建对象。
  ③ BeanFactoryPostProcessor执行
  在实例化 Bean 之前,Spring 会先执行 BeanFactoryPostProcessor,允许修改 BeanDefinition。比如替换属性值、动态修改配置。(如)
  1. <bean id="userService" >
  2.     <property name="name" value="默认名字"/>
  3. </bean>
  4. import org.springframework.beans.BeansException;
  5. import org.springframework.beans.factory.config.BeanDefinition;
  6. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
  7. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  8. import org.springframework.stereotype.Component;
  9. @Component
  10. public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
  11.     @Override
  12.     public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  13.         // 1. 拿到 BeanDefinition
  14.         BeanDefinition bd = beanFactory.getBeanDefinition("userService");
  15.         // 2. 修改属性值(替换原来 XML 里的 "默认名字")
  16.         bd.getPropertyValues().add("name", "张三");
  17.         // 3. 也可以改 scope(默认 singleton)
  18.         bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
  19.         // 4. 甚至可以换掉实现类
  20.         // bd.setBeanClassName("com.example.AnotherUserService");
  21.     }
  22. }
复制代码
  ④ BeanPostProcessor注册

  • 实例化(newInstance) → 得到一个空对象。
  • 依赖注入(populateBean) → 给对象的字段/属性赋值,比如注入 UserDao。
  • 调用 BeanPostProcessor.beforeInitialization() → 初始化前处理。
  • 执行初始化方法 → @PostConstruct、afterPropertiesSet()。
  • 调用 BeanPostProcessor.afterInitialization() → 初始化后处理(比如 AOP 代理)。
  ⑤ 实例化单例Bean(非懒加载的)
  ApplicationContext 默认会在启动时创建所有单例 Bean。
  ⑥ 发布刷新完成事件:

  • 当所有 Bean 都准备好,Spring 会发一个 ContextRefreshedEvent。
  • 这时候你写的监听器就可以收到通知。
9、说一下Spring Bean的生命周期

   基本容器BeanFacotory和扩展容器ApplicationContext的实例化实际不一样。前者是延迟初始化的方式,只有在第一次getBean的时候,才会实例化Bean。后者启动后会实例化所有的Bean定义。
  1. UserService userService = context.getBean(UserService.class);
复制代码
  在你能用到 userService 之前,Spring 已经帮它走完了以下所有步骤。

  • 容器启动,加载配置
  • 在Bean实例化之前,对BeanDefinition做修改
  • 实例化:Spring通过反射调用构造方法创建Bean对象,创建出Bean空壳对象
  • 属性赋值:Spring根据BeanDefinition里的PropetyValues,把依赖注入到对象里。
  • 初始化:1)调用Aware接口(容器把自己的信息告诉Bean);2)BeanPostProcessor前置处理,注入依赖;3)执行初始化方法(由开发者定义);4)BeanPostProcessor后置处理(常用于AOP),把Bean包装成代理对象返回。
  • 使用中:context.getBean("xxx")得到的就是最终的Bean(可能是代理对象)
  • 销毁:调用 DisposableBean.destroy()、调用配置的 destroy-method。
10、Bean定义和依赖定义有哪些方式

   ① 直接编码(最底层)
  平常很少写,但Spring内部就是用这种API来实现的。
  1. DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
  2. RootBeanDefinition beanDefinition = new RootBeanDefinition(UserService.class);
  3. beanDefinition.getPropertyValues().add("name", "张三");
  4. // 注册 BeanDefinition
  5. factory.registerBeanDefinition("userService", beanDefinition);
  6. // 获取 Bean
  7. UserService userService = (UserService) factory.getBean("userService");
复制代码
  ② 配置文件方式
  传统方式,主要是XML配置或propterties文件。Spring 启动时会解析配置文件,转成 BeanDefinition。
  ③ 注解方式(最常用)
  在类和字段上加注解,Spring 会扫描并注册到容器里。
 
参考:

[1] 沉默王二公众号

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册