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 = //定义bean
BeanDefinitionBuilder.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("构造");
}
@Autowired
public void autowire(@Value("${JAVA_HOME}") String home) { //值的注入
log.debug("依赖注入: {}", home);
}
@PostConstruct
public void init() {
log.debug("初始化");
}
@PreDestroy
public 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;
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 销毁之前执行, 如 @PreDestroy");
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 实例化之前执行, 这里返回的对象会替换掉原本的 bean");
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
log.debug("<<<<<< 实例化之后执行, 这里如果返回 false 会跳过依赖注入阶段");
// return false;
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 依赖注入阶段执行, 如 @Autowired、@Value、@Resource");
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<< 初始化之前执行, 这里返回的对象会替换掉原本的 bean, 如 @PostConstruct、@ConfigurationProperties");
return bean;
}
@Override
public 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后处理器的方式
@PostConstruct
public void init1() {
log.debug("初始化1");
}
Override 接口方式,重新接口中的方法
@Override
public void afterPropertiesSet() throws Exception {
log.debug("初始化2");
}
执行顺序:
PostConstruct — 》Override —》 @Bean
7.2、销毁的方式
@PreDestroy
public void destroy1() {
log.debug("销毁1");
}
@Override //接口功能
public void destroy() throws Exception {
log.debug("销毁2");
}
public void destroy3() {
log.debug("销毁3");
}
执行顺序: @PreDestroy—》 @Override—》@Bean
引申:
@PostConstruct
public void init1() {
log.debug("初始化1");
}
@Override
public 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 16
2. 运行时需要在 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 只能针对接口代理
// cglib
public 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
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void addUser(User user) {
userDao.addUser(user);
}
}
SUPPORTS
如果当前存在事务,则加入该事务;否则,以非事务方式继续执行。即如果上层调用方法没有开启事务,则当前方法也不会开启事务。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public User getUserById(Long id) {
return userDao.getUserById(id);
}
}
MANDATORY
如果当前存在事务,则加入该事务;否则,抛出异常。即当前方法必须在一个已有的事务中执行,否则会抛出异常。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Transactional(propagation = Propagation.MANDATORY)
@Override
public void updateUser(User user) {
userDao.updateUser(user);
}
}
REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则挂起该事务。即当前方法必须在一个新的事务中执行,如果上层调用方法已经开启了事务,则当前方法会将上层事务挂起。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void deleteUserById(Long id) {
userDao.deleteUserById(id);
}
}
NOT_SUPPORTED
以非事务方式执行操作,如果当前存在事务,则挂起该事务。即当前方法必须以非事务方式执行,如果上层调用方法已经开启了事务,则当前方法会将上层事务挂起。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public List<User> getAllUsers() {
return userDao.getAllUsers();
}
}
NEVER
以非事务方式执行操作,如果当前存在事务,则抛出异常。即当前方法必须以非事务方式执行,如果上层调用方法已经开启了事务,则当前方法会抛出异常。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Transactional(propagation = Propagation.NEVER)
@Override
public void addUsers(List<User> userList) {
for (User user : userList) {
userDao.addUser(user);
}
}
}
NESTED
如果当前存在事务,则在嵌套事务内执行;否则,创建一个新事务。嵌套事务是外层事务的一部分,它可以独立提交或回滚,但是只有当外层事务提交时,嵌套事务才会被提交。如果外层事务回滚,则嵌套事务也会被回滚。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Transactional(propagation = Propagation.NESTED)
@Override
public void updateUserWithAddress(User user, Address address) {
userDao.updateUser(user); // 更新用户信息
userDao.addAddress(address); // 添加地址信息
}
}
在上述示例代码中,我们使用了Spring的@Transactional注解来开启事务,并设置了不同的传播行为。每个传播行为都适用于不同的场景,例如REQUIRED适用于大多数情况下,而MANDATORY适用于必须在一个已有的事务中执行的情况下。注释中对方法的作用和传播行为进行了解
为了防止事务对数据资源的占用:(事务时间过长,占用连接),一般在代码中添加事务时,只加在针对数据库操作的方法上,以实现更好的利用,但是在非事务方法调用事务方法的情况下很容易让事务失效。需要保证一下两点
- 事务注解
- 在非事务方法中调用的事务方法必须是代理对象
可以自己注入自己,实现自我代理。