BeanFactory的所有方法:(Ctrl+F12)
image.png

实现类:DefaultListableBeanFactory
ApplicationContext:
image.png

  • MessageSourse:国际化
  • ResoursePatternResolver:通配符匹配资源
  • ApplicationEventPublisher:发布事件对象
  • EnvironmentCapable:Spring中的环境信息

1、MessageSourse
Resource配置语言包
image.png

  1. System.out.println(context.getMessage("hi", null, Locale.CHINA));
  2. System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
  3. System.out.println(context.getMessage("hi", null, Locale.JAPANESE));

image.png

2、ResoursePatternResolver

  1. Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
  2. //正常情况下无法找到Jar包中的内容,classpath后加“ * ”后即可
  3. for (Resource resource : resources) {
  4. System.out.println(resource);
  5. }

image.png
3、EnvironmentCapable

获取环境变量和配置信息

  1. System.out.println(context.getEnvironment().getProperty("java_home"));
  2. System.out.println(context.getEnvironment().getProperty("server.port"));

image.png

4、ApplicationEventPublisher

  • 定义事件发布者 ```java @Autowired private ApplicationEventPublisher context;

public void register() { log.debug(“用户注册”); context.publishEvent(new UserRegisteredEvent(this)); }

  1. - **定义监听者**
  2. ```java
  3. @EventListener //监听者必需的注解
  4. public void aaa(UserRegisteredEvent event) {
  5. log.debug("{}", event);
  6. log.debug("发送短信");
  7. }
  • 调试
    1. context.getBean(Component1.class).register(); //获取Bean,并进行注册
    image.png

2、容器实现

2.1、BeanFactory实现的特点

  • 基本实现
    1. DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    2. //内部无bean,需要事先定义
    3. // bean 的定义(class, scope, 初始化, 销毁)
    4. AbstractBeanDefinition beanDefinition = //定义bean
    5. BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
    6. beanFactory.registerBeanDefinition("config", beanDefinition); //注册bean

    缺陷:获取到的bean有限

  1. // 给 BeanFactory 添加一些常用的后处理器
  2. AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
  3. // BeanFactory 后处理器主要功能,补充了一些 bean 定义
  4. beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
  5. beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
  6. });
  7. // Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...
  8. beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
  9. .sorted(beanFactory.getDependencyComparator())
  10. .forEach(beanPostProcessor -> {
  11. System.out.println(">>>>" + beanPostProcessor);
  12. beanFactory.addBeanPostProcessor(beanPostProcessor);
  13. });
  14. for (String name : beanFactory.getBeanDefinitionNames()) {
  15. System.out.println(name);
  16. }

一般情况下需要使用后处理器来扩展beanFactory的功能

image.png
beanFactory后处理器与Bean后处理器的区别:

  • Beanfactory是将后处理器注册到Bean中
  • Bean后处理器实现具体的功能

知识点:
在获取Bean时,spring只会获取Bean的名字,而在具体使用时,才会进行实例构造,这种方式被称为懒加载。 :::tips beanFactory.preInstantiateSingletons(); // 准备好所有单例 :::

总结:

beanFactory 不会做的事
1. 不会主动调用 BeanFactory 后处理器
2. 不会主动添加 Bean 后处理器
3. 不会主动初始化单例
4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }
bean 后处理器会有排序的逻辑

2.2、ApplicationContext的常见实现和用法

2.3、内嵌容器、注册DispatcherServlet

3、Bean生命周期

3.1、Bean生命周期及后处理器

  1. public LifeCycleBean() {
  2. log.debug("构造");
  3. }
  4. @Autowired
  5. public void autowire(@Value("${JAVA_HOME}") String home) { //值的注入
  6. log.debug("依赖注入: {}", home);
  7. }
  8. @PostConstruct
  9. public void init() {
  10. log.debug("初始化");
  11. }
  12. @PreDestroy
  13. public void destroy() {
  14. log.debug("销毁");
  15. }

构造—》依赖注入—》初始化—》销毁

后处理器:

  1. package com.itheima.a03;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import org.springframework.beans.BeansException;
  5. import org.springframework.beans.PropertyValues;
  6. import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
  7. import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
  8. import org.springframework.stereotype.Component;
  9. @Component
  10. public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
  11. private static final Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);
  12. @Override
  13. public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
  14. if (beanName.equals("lifeCycleBean"))
  15. log.debug("<<<<<< 销毁之前执行, 如 @PreDestroy");
  16. }
  17. @Override
  18. public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
  19. if (beanName.equals("lifeCycleBean"))
  20. log.debug("<<<<<< 实例化之前执行, 这里返回的对象会替换掉原本的 bean");
  21. return null;
  22. }
  23. @Override
  24. public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
  25. if (beanName.equals("lifeCycleBean")) {
  26. log.debug("<<<<<< 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段");
  27. // return false;
  28. }
  29. return true;
  30. }
  31. @Override
  32. public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
  33. if (beanName.equals("lifeCycleBean"))
  34. log.debug("<<<<<< 依赖注入阶段执行, 如 @Autowired、@Value、@Resource");
  35. return pvs;
  36. }
  37. @Override
  38. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  39. if (beanName.equals("lifeCycleBean"))
  40. log.debug("<<<<<< 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties");
  41. return bean;
  42. }
  43. @Override
  44. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  45. if (beanName.equals("lifeCycleBean"))
  46. log.debug("<<<<<< 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强");
  47. return bean;
  48. }
  49. }

在Bean的四个过程中,会有很多增强,这些增强是由后处理器构成的

image.png

3.2、模板方法

image.png

对于方法中确定的可以写死 不确定的部分可以抽象成接口 此种扩展方式被称为模板方法,有静有动。

7、初始化与销毁

7.1、初始的方式

  • 注解@Bean的方式

    1. @Bean(initMethod = "init3")
    2. public Bean1 bean1() {
    3. return new Bean1();
    4. }
  • @PostConstruct bean后处理器的方式

    1. @PostConstruct
    2. public void init1() {
    3. log.debug("初始化1");
    4. }
  • Override 接口方式,重新接口中的方法

    1. @Override
    2. public void afterPropertiesSet() throws Exception {
    3. log.debug("初始化2");
    4. }

    执行顺序:
    image.png

    PostConstruct — 》Override —》 @Bean

7.2、销毁的方式

  1. @PreDestroy
  2. public void destroy1() {
  3. log.debug("销毁1");
  4. }
  5. @Override //接口功能
  6. public void destroy() throws Exception {
  7. log.debug("销毁2");
  8. }
  9. public void destroy3() {
  10. log.debug("销毁3");
  11. }

执行顺序: @PreDestroy—》 @Override—》@Bean

引申:

  1. @PostConstruct
  2. public void init1() {
  3. log.debug("初始化1");
  4. }
  5. @Override
  6. public void afterPropertiesSet() throws Exception {
  7. log.debug("初始化2");
  8. }

AutoWired 注解执行顺序在上面两个注解之间

8、Scope

singleton, prototype, request, session, application 当前的Scope域

  • singleton 单一对象,SpringContext创建时创建,销毁时销毁
  • prototype: 不同对象,每次使用时创建,其对象由容器管理,可以调用销毁方法
  • request:每次请求来时将request放进web的request中
  • session:每次会话刷新,会话创建时将其放入会话中,超时后也会销毁
  • application:serverletContext创建时创建,destroy中 在spring中并没有相关实现

9、AOP

9.1、aspectj 代理增强

pom文件引入:

  1. <plugin>
  2. <groupId>org.codehaus.mojo</groupId>
  3. <artifactId>aspectj-maven-plugin</artifactId>
  4. <version>1.14.0</version>
  5. <configuration>
  6. <complianceLevel>1.8</complianceLevel>
  7. <source>8</source>
  8. <target>8</target>
  9. <showWeaveInfo>true</showWeaveInfo>
  10. <verbose>true</verbose>
  11. <Xlint>ignore</Xlint>
  12. <encoding>UTF-8</encoding>
  13. </configuration>
  14. <executions>
  15. <execution>
  16. <goals>
  17. <!-- use this goal to weave all your main classes -->
  18. <goal>compile</goal>
  19. <!-- use this goal to weave all your test classes -->
  20. <goal>test-compile</goal>
  21. </goals>
  22. </execution>
  23. </executions>
  24. </plugin>
  • 代码编写

    1. @Aspect // ⬅️注意此切面并未被 Spring 管理
    2. public class MyAspect {
    3. private static final Logger log = LoggerFactory.getLogger(MyAspect.class);
    4. @Before("execution(* com.itheima.service.MyService.foo())")
    5. public void before() {
    6. log.debug("before()");
    7. }
    8. }
  • 最终结果

    1. 20:31:55.446 [main] DEBUG com.itheima.aop.MyAspect - before()
    2. 20:31:55.454 [main] DEBUG com.itheima.service.MyService - foo()

增强成功:

  • 一般情况下的增强是通过重写方法,但是这种增强属于编译器层面的增强,因此及时是 static 静态方法,依然可以增强。
  • 此种增强是通过在编译过程总增强,不适用动态代理,和Spring容器无关

使用javaagent进行代理

  1. 1. 版本选择了 java 8, 因为目前的 aspectj-maven-plugin 1.14.0 最高只支持到 java 16
  2. 2. 运行时需要在 VM options 里加入 -javaagent:C:/Users/manyh/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspec

MyService 并非代理, 但 foo 方法也被增强了, 做增强的 java agent, 在加载类时, 修改了 class 字节码。

11、Aop之proxy

  1. JDK代理

    1. public class JdkProxyDemo {
    2. interface Foo {
    3. void foo();
    4. }
    5. static final class Target implements Foo {
    6. public void foo() {
    7. System.out.println("target foo");
    8. }
    9. }
    10. // jdk 只能针对接口代理
    11. // cglib
    12. public static void main(String[] param) throws IOException {
    13. // 目标对象
    14. Target target = new Target();
    15. ClassLoader loader = JdkProxyDemo.class.getClassLoader(); // 用来加载在运行期间动态生成的字节码
    16. Foo proxy = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, (p, method, args) -> {//代理类,方法,参数
    17. //类加载器,定义实现接口的数组,实现接口的方法
    18. System.out.println("before...");
    19. // 目标.方法(参数) (正常调用)
    20. // 方法.invoke(目标, 参数); (反射调用)
    21. Object result = method.invoke(target, args);
    22. System.out.println("after....");
    23. return result; // 让代理也返回目标方法执行的结果
    24. });
    25. System.out.println(proxy.getClass());
    26. proxy.foo();
    27. System.in.read();
    28. }
    29. }

    总结:

  • 目标类和代理类是兄弟关系,都实现了同一个接口
  • 目标类可以用final修饰
  1. Cglib代理

    1. public class CglibProxyDemo {
    2. static class Target {
    3. public void foo() {
    4. System.out.println("target foo");
    5. }
    6. }
    7. // 代理是子类型, 目标是父类型
    8. public static void main(String[] param) {
    9. // Target target = new Target();
    10. Target proxy = (Target) Enhancer.create(Target.class, (MethodInterceptor) (p, method, args, methodProxy) -> {
    11. System.out.println("before...");
    12. // Object result = method.invoke(target, args); // 用方法反射调用目标
    13. // methodProxy 它可以避免反射调用
    14. // Object result = methodProxy.invoke(target, args); // 内部没有用反射, 需要目标 (spring)
    15. Object result = methodProxy.invokeSuper(p, args); // 内部没有用反射, 需要代理
    16. System.out.println("after...");
    17. return result;
    18. });
    19. proxy.foo();
    20. }
    21. }

    总结:

  • 代理是子类型, 目标是父类型
  • 三种代理目标方法的方式 ```java Object result = method.invoke(target, args); // 用方法反射调用目标 //反射影响性能
    // methodProxy 它可以避免反射调用 Object result = methodProxy.invoke(target, args); // 内部没有用反射, 需要目标 (spring) Object result = methodProxy.invokeSuper(p, args); // 内部没有用反射, 需要代理
  1. <a name="M9RFZ"></a>
  2. # spring 事务类型
  3. <a name="OsPtY"></a>
  4. ## 事务传播类型
  5. <a name="REQUIRED"></a>
  6. ### REQUIRED
  7. > 如果当前存在事务,则加入该事务;否则,创建一个新事务。这是最常用的传播行为。
  8. ```java
  9. @Service
  10. public class UserServiceImpl implements UserService {
  11. @Autowired
  12. private UserDao userDao;
  13. @Transactional(propagation = Propagation.REQUIRED)
  14. @Override
  15. public void addUser(User user) {
  16. userDao.addUser(user);
  17. }
  18. }

SUPPORTS

如果当前存在事务,则加入该事务;否则,以非事务方式继续执行。即如果上层调用方法没有开启事务,则当前方法也不会开启事务。

  1. @Service
  2. public class UserServiceImpl implements UserService {
  3. @Autowired
  4. private UserDao userDao;
  5. @Transactional(propagation = Propagation.SUPPORTS)
  6. @Override
  7. public User getUserById(Long id) {
  8. return userDao.getUserById(id);
  9. }
  10. }

MANDATORY

如果当前存在事务,则加入该事务;否则,抛出异常。即当前方法必须在一个已有的事务中执行,否则会抛出异常。

  1. @Service
  2. public class UserServiceImpl implements UserService {
  3. @Autowired
  4. private UserDao userDao;
  5. @Transactional(propagation = Propagation.MANDATORY)
  6. @Override
  7. public void updateUser(User user) {
  8. userDao.updateUser(user);
  9. }
  10. }

REQUIRES_NEW

创建一个新的事务,如果当前存在事务,则挂起该事务。即当前方法必须在一个新的事务中执行,如果上层调用方法已经开启了事务,则当前方法会将上层事务挂起。

  1. @Service
  2. public class UserServiceImpl implements UserService {
  3. @Autowired
  4. private UserDao userDao;
  5. @Transactional(propagation = Propagation.REQUIRES_NEW)
  6. @Override
  7. public void deleteUserById(Long id) {
  8. userDao.deleteUserById(id);
  9. }
  10. }

NOT_SUPPORTED

以非事务方式执行操作,如果当前存在事务,则挂起该事务。即当前方法必须以非事务方式执行,如果上层调用方法已经开启了事务,则当前方法会将上层事务挂起。

  1. @Service
  2. public class UserServiceImpl implements UserService {
  3. @Autowired
  4. private UserDao userDao;
  5. @Transactional(propagation = Propagation.NOT_SUPPORTED)
  6. @Override
  7. public List<User> getAllUsers() {
  8. return userDao.getAllUsers();
  9. }
  10. }

NEVER

以非事务方式执行操作,如果当前存在事务,则抛出异常。即当前方法必须以非事务方式执行,如果上层调用方法已经开启了事务,则当前方法会抛出异常。

  1. @Service
  2. public class UserServiceImpl implements UserService {
  3. @Autowired
  4. private UserDao userDao;
  5. @Transactional(propagation = Propagation.NEVER)
  6. @Override
  7. public void addUsers(List<User> userList) {
  8. for (User user : userList) {
  9. userDao.addUser(user);
  10. }
  11. }
  12. }

NESTED

如果当前存在事务,则在嵌套事务内执行;否则,创建一个新事务。嵌套事务是外层事务的一部分,它可以独立提交或回滚,但是只有当外层事务提交时,嵌套事务才会被提交。如果外层事务回滚,则嵌套事务也会被回滚。

  1. @Service
  2. public class UserServiceImpl implements UserService {
  3. @Autowired
  4. private UserDao userDao;
  5. @Transactional(propagation = Propagation.NESTED)
  6. @Override
  7. public void updateUserWithAddress(User user, Address address) {
  8. userDao.updateUser(user); // 更新用户信息
  9. userDao.addAddress(address); // 添加地址信息
  10. }
  11. }

在上述示例代码中,我们使用了Spring的@Transactional注解来开启事务,并设置了不同的传播行为。每个传播行为都适用于不同的场景,例如REQUIRED适用于大多数情况下,而MANDATORY适用于必须在一个已有的事务中执行的情况下。注释中对方法的作用和传播行为进行了解

为了防止事务对数据资源的占用:(事务时间过长,占用连接),一般在代码中添加事务时,只加在针对数据库操作的方法上,以实现更好的利用,但是在非事务方法调用事务方法的情况下很容易让事务失效。需要保证一下两点

  • 事务注解
  • 在非事务方法中调用的事务方法必须是代理对象

可以自己注入自己,实现自我代理。