BeanFactory的所有方法:(Ctrl+F12)
实现类:DefaultListableBeanFactory
ApplicationContext:
- MessageSourse:国际化
- ResoursePatternResolver:通配符匹配资源
- ApplicationEventPublisher:发布事件对象
- EnvironmentCapable:Spring中的环境信息
1、MessageSourse
Resource配置语言包
System.out.println(context.getMessage("hi", null, Locale.CHINA));System.out.println(context.getMessage("hi", null, Locale.ENGLISH));System.out.println(context.getMessage("hi", null, Locale.JAPANESE));

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

3、EnvironmentCapable
获取环境变量和配置信息
System.out.println(context.getEnvironment().getProperty("java_home"));System.out.println(context.getEnvironment().getProperty("server.port"));

4、ApplicationEventPublisher
- 定义事件发布者 ```java @Autowired private ApplicationEventPublisher context;
public void register() { log.debug(“用户注册”); context.publishEvent(new UserRegisteredEvent(this)); }
- **定义监听者**```java@EventListener //监听者必需的注解public void aaa(UserRegisteredEvent event) {log.debug("{}", event);log.debug("发送短信");}
- 调试
context.getBean(Component1.class).register(); //获取Bean,并进行注册

2、容器实现
2.1、BeanFactory实现的特点
- 基本实现
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();//内部无bean,需要事先定义// bean 的定义(class, scope, 初始化, 销毁)AbstractBeanDefinition beanDefinition = //定义beanBeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();beanFactory.registerBeanDefinition("config", beanDefinition); //注册bean
缺陷:获取到的bean有限
// 给 BeanFactory 添加一些常用的后处理器AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);// BeanFactory 后处理器主要功能,补充了一些 bean 定义beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);});// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().sorted(beanFactory.getDependencyComparator()).forEach(beanPostProcessor -> {System.out.println(">>>>" + beanPostProcessor);beanFactory.addBeanPostProcessor(beanPostProcessor);});for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}
一般情况下需要使用后处理器来扩展beanFactory的功能

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生命周期及后处理器
public LifeCycleBean() {log.debug("构造");}@Autowiredpublic void autowire(@Value("${JAVA_HOME}") String home) { //值的注入log.debug("依赖注入: {}", home);}@PostConstructpublic void init() {log.debug("初始化");}@PreDestroypublic void destroy() {log.debug("销毁");}
构造—》依赖注入—》初始化—》销毁
后处理器:
package com.itheima.a03;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.BeansException;import org.springframework.beans.PropertyValues;import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;import org.springframework.stereotype.Component;@Componentpublic class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {private static final Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);@Overridepublic void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean"))log.debug("<<<<<< 销毁之前执行, 如 @PreDestroy");}@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean"))log.debug("<<<<<< 实例化之前执行, 这里返回的对象会替换掉原本的 bean");return null;}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean")) {log.debug("<<<<<< 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段");// return false;}return true;}@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean"))log.debug("<<<<<< 依赖注入阶段执行, 如 @Autowired、@Value、@Resource");return pvs;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean"))log.debug("<<<<<< 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean"))log.debug("<<<<<< 初始化之后执行, 这里返回的对象会替换掉原本的 bean, 如代理增强");return bean;}}
在Bean的四个过程中,会有很多增强,这些增强是由后处理器构成的

3.2、模板方法

对于方法中确定的可以写死 不确定的部分可以抽象成接口 此种扩展方式被称为模板方法,有静有动。
7、初始化与销毁
7.1、初始的方式
注解@Bean的方式
@Bean(initMethod = "init3")public Bean1 bean1() {return new Bean1();}
@PostConstruct bean后处理器的方式
@PostConstructpublic void init1() {log.debug("初始化1");}
Override 接口方式,重新接口中的方法
@Overridepublic void afterPropertiesSet() throws Exception {log.debug("初始化2");}
执行顺序:

PostConstruct — 》Override —》 @Bean
7.2、销毁的方式
@PreDestroypublic void destroy1() {log.debug("销毁1");}@Override //接口功能public void destroy() throws Exception {log.debug("销毁2");}public void destroy3() {log.debug("销毁3");}
执行顺序: @PreDestroy—》 @Override—》@Bean
引申:
@PostConstructpublic void init1() {log.debug("初始化1");}@Overridepublic void afterPropertiesSet() throws Exception {log.debug("初始化2");}
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文件引入:
<plugin><groupId>org.codehaus.mojo</groupId><artifactId>aspectj-maven-plugin</artifactId><version>1.14.0</version><configuration><complianceLevel>1.8</complianceLevel><source>8</source><target>8</target><showWeaveInfo>true</showWeaveInfo><verbose>true</verbose><Xlint>ignore</Xlint><encoding>UTF-8</encoding></configuration><executions><execution><goals><!-- use this goal to weave all your main classes --><goal>compile</goal><!-- use this goal to weave all your test classes --><goal>test-compile</goal></goals></execution></executions></plugin>
代码编写
@Aspect // ⬅️注意此切面并未被 Spring 管理public class MyAspect {private static final Logger log = LoggerFactory.getLogger(MyAspect.class);@Before("execution(* com.itheima.service.MyService.foo())")public void before() {log.debug("before()");}}
最终结果
20:31:55.446 [main] DEBUG com.itheima.aop.MyAspect - before()20:31:55.454 [main] DEBUG com.itheima.service.MyService - foo()
增强成功:
- 一般情况下的增强是通过重写方法,但是这种增强属于编译器层面的增强,因此及时是 static 静态方法,依然可以增强。
- 此种增强是通过在编译过程总增强,不适用动态代理,和Spring容器无关
使用javaagent进行代理
1. 版本选择了 java 8, 因为目前的 aspectj-maven-plugin 1.14.0 最高只支持到 java 162. 运行时需要在 VM options 里加入 -javaagent:C:/Users/manyh/.m2/repository/org/aspectj/aspectjweaver/1.9.7/aspec
MyService 并非代理, 但 foo 方法也被增强了, 做增强的 java agent, 在加载类时, 修改了 class 字节码。
11、Aop之proxy
JDK代理
public class JdkProxyDemo {interface Foo {void foo();}static final class Target implements Foo {public void foo() {System.out.println("target foo");}}// jdk 只能针对接口代理// cglibpublic static void main(String[] param) throws IOException {// 目标对象Target target = new Target();ClassLoader loader = JdkProxyDemo.class.getClassLoader(); // 用来加载在运行期间动态生成的字节码Foo proxy = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, (p, method, args) -> {//代理类,方法,参数//类加载器,定义实现接口的数组,实现接口的方法System.out.println("before...");// 目标.方法(参数) (正常调用)// 方法.invoke(目标, 参数); (反射调用)Object result = method.invoke(target, args);System.out.println("after....");return result; // 让代理也返回目标方法执行的结果});System.out.println(proxy.getClass());proxy.foo();System.in.read();}}
总结:
- 目标类和代理类是兄弟关系,都实现了同一个接口
- 目标类可以用final修饰
Cglib代理
public class CglibProxyDemo {static class Target {public void foo() {System.out.println("target foo");}}// 代理是子类型, 目标是父类型public static void main(String[] param) {// Target target = new Target();Target proxy = (Target) Enhancer.create(Target.class, (MethodInterceptor) (p, method, args, methodProxy) -> {System.out.println("before...");// Object result = method.invoke(target, args); // 用方法反射调用目标// methodProxy 它可以避免反射调用// Object result = methodProxy.invoke(target, args); // 内部没有用反射, 需要目标 (spring)Object result = methodProxy.invokeSuper(p, args); // 内部没有用反射, 需要代理System.out.println("after...");return result;});proxy.foo();}}
总结:
- 代理是子类型, 目标是父类型
- 三种代理目标方法的方式
```java
Object result = method.invoke(target, args); // 用方法反射调用目标
//反射影响性能
// methodProxy 它可以避免反射调用 Object result = methodProxy.invoke(target, args); // 内部没有用反射, 需要目标 (spring) Object result = methodProxy.invokeSuper(p, args); // 内部没有用反射, 需要代理
<a name="M9RFZ"></a># spring 事务类型<a name="OsPtY"></a>## 事务传播类型<a name="REQUIRED"></a>### REQUIRED> 如果当前存在事务,则加入该事务;否则,创建一个新事务。这是最常用的传播行为。```java@Servicepublic class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Transactional(propagation = Propagation.REQUIRED)@Overridepublic void addUser(User user) {userDao.addUser(user);}}
SUPPORTS
如果当前存在事务,则加入该事务;否则,以非事务方式继续执行。即如果上层调用方法没有开启事务,则当前方法也不会开启事务。
@Servicepublic class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Transactional(propagation = Propagation.SUPPORTS)@Overridepublic User getUserById(Long id) {return userDao.getUserById(id);}}
MANDATORY
如果当前存在事务,则加入该事务;否则,抛出异常。即当前方法必须在一个已有的事务中执行,否则会抛出异常。
@Servicepublic class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Transactional(propagation = Propagation.MANDATORY)@Overridepublic void updateUser(User user) {userDao.updateUser(user);}}
REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则挂起该事务。即当前方法必须在一个新的事务中执行,如果上层调用方法已经开启了事务,则当前方法会将上层事务挂起。
@Servicepublic class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Transactional(propagation = Propagation.REQUIRES_NEW)@Overridepublic void deleteUserById(Long id) {userDao.deleteUserById(id);}}
NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,则挂起该事务。即当前方法必须以非事务方式执行,如果上层调用方法已经开启了事务,则当前方法会将上层事务挂起。
@Servicepublic class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Transactional(propagation = Propagation.NOT_SUPPORTED)@Overridepublic List<User> getAllUsers() {return userDao.getAllUsers();}}
NEVER
以非事务方式执行操作,如果当前存在事务,则抛出异常。即当前方法必须以非事务方式执行,如果上层调用方法已经开启了事务,则当前方法会抛出异常。
@Servicepublic class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Transactional(propagation = Propagation.NEVER)@Overridepublic void addUsers(List<User> userList) {for (User user : userList) {userDao.addUser(user);}}}
NESTED
如果当前存在事务,则在嵌套事务内执行;否则,创建一个新事务。嵌套事务是外层事务的一部分,它可以独立提交或回滚,但是只有当外层事务提交时,嵌套事务才会被提交。如果外层事务回滚,则嵌套事务也会被回滚。
@Servicepublic class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Transactional(propagation = Propagation.NESTED)@Overridepublic void updateUserWithAddress(User user, Address address) {userDao.updateUser(user); // 更新用户信息userDao.addAddress(address); // 添加地址信息}}
在上述示例代码中,我们使用了Spring的@Transactional注解来开启事务,并设置了不同的传播行为。每个传播行为都适用于不同的场景,例如REQUIRED适用于大多数情况下,而MANDATORY适用于必须在一个已有的事务中执行的情况下。注释中对方法的作用和传播行为进行了解
为了防止事务对数据资源的占用:(事务时间过长,占用连接),一般在代码中添加事务时,只加在针对数据库操作的方法上,以实现更好的利用,但是在非事务方法调用事务方法的情况下很容易让事务失效。需要保证一下两点
- 事务注解
- 在非事务方法中调用的事务方法必须是代理对象
可以自己注入自己,实现自我代理。
