赞
踩
@Scope("prototype")
//@Scope(WebApplicationContext.SCOPE_REQUEST)
//@RequestScope()
// WebApplicationContext.SCOPE_REQUEST== request
// String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
// String SCOPE_REQUEST = "request";
// String SCOPE_SESSION = "session";
// String SCOPE_APPLICATION = "application";
// String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
// String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
// String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
3. request作用域:每次Http请求时都会创建一个新的 Bean该作用域仅适应于WebApplicationContext环境
4. session作用域:同一个Http Session共享-个Bean对象
不同的Session拥有不同的Bean对象,仅适用于WebApplicationContext环境
5. application作用域:
全局的Web作用域,类似于Servlet中的Application
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { if (this.logger.isTraceEnabled()) { this.logger.trace("Creating instance of bean '" + beanName + "'"); } RootBeanDefinition mbdToUse = mbd; //确定并加载bean的class Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } try { // 验证以及准备需要覆盖的方法 mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException var9) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9); } Object beanInstance; try { // getBeanPostProcessors 一个机会来返回代理对象来代替真正的Bean实例,在这里实现创建代理对象功能 beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse); if (beanInstance != null) { return beanInstance; } } catch (Throwable var10) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10); } try { //创建bean beanInstance = this.doCreateBean(beanName, mbdToUse, args); if (this.logger.isTraceEnabled()) { this.logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) { throw var7; } catch (Throwable var8) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8); } }
doCreateBean 的源码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { //实例化bean, BeanWrapper对象提供了设置和获取属性值的功能 BeanWrapper instanceWrapper = null; //如果RootBeanDefinition 是单例,则移除未完成的FactoryBean实例的缓存 if (mbd.isSingleton()) { instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { // 创建bean实列 instanceWrapper = this.createBeanInstance(beanName, mbd, args); } //获取BeanWrapper中封装的Object对象,其实就是bean对象的实例 Object bean = instanceWrapper.getWrappedInstance(); //获取BeanWrapper中封装bean的Class Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } //应用MergedBeanDefinitionPostProcessor后处理器,合并bean的定义信息 //Autowire等注解信息就是在这步完成预解析,并且将注解需要的信息放入缓存 synchronized(mbd.postProcessingLock) { if (!mbd.postProcessed) { try { this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable var17) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17); } mbd.postProcessed = true; } } boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName); if (earlySingletonExposure) { if (this.logger.isTraceEnabled()) { this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } //为了避免循环依赖,在bean初始化完成前,就将创建bean 实例的ObjectFactory放入工厂缓存(singletonFactories) this.addSingletonFactory(beanName, () -> { return this.getEarlyBeanReference(beanName, mbd, bean); }); } // 对bean 属性进行赋值 Object exposedObject = bean; try { this.populateBean(beanName, mbd, instanceWrapper); // 调用初始化方法 如 init-method 注入aware对象 exposedObject = this.initializeBean(beanName, exposedObject, mbd); } catch (Throwable var18) { if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) { throw (BeanCreationException)var18; } throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18); } if (earlySingletonExposure) { // 如果存在循环依赖 当前bean被其他类在初始化的过程中扫描过 Object earlySingletonReference = this.getSingleton(beanName, false); if (earlySingletonReference != null) { // 如果exposedObject 没有在其他方法中被增强过 if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) { //依赖检测 String[] dependentBeans = this.getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length); String[] var12 = dependentBeans; int var13 = dependentBeans.length; for(int var14 = 0; var14 < var13; ++var14) { String dependentBean = var12[var14]; if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } // 如果actualDependentBeans 不为空 则表示依赖的bean没用被创建完,还存在循环依赖 if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example."); } } } } try { // 注册DisposableBean 以便在销毁时调用 this.registerDisposableBeanIfNecessary(beanName, bean, mbd); return exposedObject; } catch (BeanDefinitionValidationException var16) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16); } }
bean 的初始化会自动调用方法initializeBean() ,在之前的博客中也记录到过,想要对一个bean初始化完成后做一些扩展 只需要实现一个
InitializingBean 接口类,重写一个他的 afterPropertiesSet () 方法,就能实现.下面是 initializeBean 方法源码
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(() -> { // 重点方法,根据beanName 对这个bean对象进行扩展 this.invokeAwareMethods(beanName, bean); return null; }, this.getAccessControlContext()); } else { this.invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName); } try { this.invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable var6) { throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
invokeAwareMethods 方法源码
private void invokeAwareMethods(String beanName, Object bean) { if (bean instanceof Aware) { // 如果当前的bean类型是属于BeanNameAware 那么将当前的beanName 设置到BeanNameAware 中 if (bean instanceof BeanNameAware) { ((BeanNameAware)bean).setBeanName(beanName); } // 如果当前的bean类型是属于BeanClassLoaderAware 那么将当前对象的classloader 注册到当前实例对象的beanClassLoader 中 if (bean instanceof BeanClassLoaderAware) { ClassLoader bcl = this.getBeanClassLoader(); if (bcl != null) { ((BeanClassLoaderAware)bean).setBeanClassLoader(bcl); } } if (bean instanceof BeanFactoryAware) { //是将当前对象注册到BeanFactory 中,这个对象就能获得一个beanFactory 对象的引用. ((BeanFactoryAware)bean).setBeanFactory(this); } } }
invokeInitMethods 方法源码如下
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { // 判断当前bean是否实现了InitializingBean 接口 如果是的话,需要调用afterPropertiesSet 方法 boolean isInitializingBean = bean instanceof InitializingBean; if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (this.logger.isTraceEnabled()) { this.logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } // 如果安全模式不为空,则进入if if (System.getSecurityManager() != null) { try { // 初始化方法 AccessController.doPrivileged(() -> { ((InitializingBean)bean).afterPropertiesSet(); return null; }, this.getAccessControlContext()); } catch (PrivilegedActionException var6) { throw var6.getException(); } } else { // 如果安全模式为空则进入 else ((InitializingBean)bean).afterPropertiesSet(); } } // 判断是否指定了init - method if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { // 利用反射机制执行指定方法 this.invokeCustomInitMethod(beanName, bean, mbd); } } }
如果是BeanFactory容器,需要主劫调用destroySingletons()方法
通知BeanFactory容器去执行相应的销毁方法
如果是ApplicationContext容器,需要主劫调用registerShutdownHook()方法 告知ApplicationContext 容器执行相应的销毁方法
源码版本:Spring 5.2.2.RELEASE
Bean对象的生命周期
IOC 是什么
DI 的理解
SpringIOC 的优点
1.使用方便,拿来即用 无需显式的创建和销毁的过程.
2. 提供众多服务 比如事务管理、消息服务等
3. 提供单例模式的支持
4. 提供AOP抽象 利用它实现权限拦截、运行期监控等功能
5. 更符合面向对象的设计法则
6. 低侵,入式设计 代码污染极低 降低业务对象替换的复杂性
SpringIOC 的注入方法
1.构造方法注入
主要是依赖于构造方法去实现,构造方法可以是有参的也可以是无参的我们平时new对象时就是通过类的构造方法来创建类对象的
每个类对象默认会有一个无参的构造方法
构造器注入
注意 这里的xml 里面的属性是 constructor 构造器的意思 和用set方法设置值是不一样的
2.set注入
这里的key-Value 是property -value 不是构造器注入
3.接口注入
接口注入方式是比较古老的注入方式
因为它需要被依赖的对象实现不必要的接口,带有侵入性
因此现在已经被完全舍弃
Spring AOP目前提供了三种配置方式
1.基于Java API的方式
1.1 先定一个普通的类 ,自定义一个方法
1.2 定义一个方法类实现接口
实现接口MethodBeforeAdvice,AfterReturningAdvice 并重写方法
1.3 配置xml
2.基于 @AspectJ (Java) 的方式
2.1 添加引用依赖
<!-- 添加 aop 的依赖-->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId> aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
2.2 开启注解
两种方式二选其一
2.3 自定义Aspect
普通的方法切面
@Component @Aspect public class ControllerAop { @Pointcut("execution(* com.myself.seckill.service.impl.OrderServiceImpl.*(..)) ") public void myCut() { } @Before("myCut()") public void before(){ System.out.println("before--->"); } @After("myCut()") public void after(){ System.out.println("after--->"); } }
基于注解的方式进行切面
首先自定义一个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLogAop {
String value() default "";
}
再自定义基于注解的拦截器
@Aspect @Component public class MyLogAopAspect { //注解的方式 @annotation 表达式 , 方法或者类用 execution 表达式 @Pointcut("@annotation(com.myself.seckill.myaop.MyLogAop)") public void MyPointCut(){ } @Before("MyPointCut()") public void MyBefore(){ System.out.println("MyBefore---> MyPointCut--->"); } @After("MyPointCut()") public void MyAfter(){ System.out.println("MyAfter---> MyPointCut--->"); } }
最后在启动类上添加注解
//开启aop切面的注解
@EnabledAspectJAutoProxy
使用方法
在任何想要实现自定义注解切面的方法上添加自定义注解
加上一开始的自定义的切面
当访问这个接口的时候,效果如下
3. 基于XML 的方式
代理类的源码如下
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // isOptimize 是否等待优化 默认false ,isProxyTargetClass 是否是代理对象 if (IN_NATIVE_IMAGE || !config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) { return new JdkDynamicAopProxy(config); } else { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation."); } else { // 如果目标类不是一个接口类并且不是一个代理类 那么就直接创建一个CGlib代理对象 否则就创建一个JDK代理对象 return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config)); } } } // 没有用户提供的代理接口 判断有没有获取代理接口的类 private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) { Class<?>[] ifcs = config.getProxiedInterfaces(); return ifcs.length == 0 || ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0]); }
spring 自带的监控功能
springboot 内置tomcat 他是如何启动的?
直接上源码
public ConfigurableApplicationContext run(String... args) { // 1.创建并启动计时监控类 // 此计时器是为了监控并记录Spring Boot应用启动的时间它会记录当前任务的名称,然后开启计时器 StopWatch stopWatch = new StopWatch(); stopWatch.start(); DefaultBootstrapContext bootstrapContext = this.createBootstrapContext(); // 2.此过程声明应用上下文对象 ConfigurableApplicationContext context = null; //3.设置系统属性headless的值 设置Java.awt.headless = true, //其中awt (Abstract Window Toolkit)含义是抽象窗口工具集, //设置为true表示运行一-个headless服务器可以用它来作一-些简单的图像处理 this.configureHeadlessProperty(); //4. 创建所有Spring运行监听器并发布应用启动事件 此过程用于获取配置的监听器名称并实例化所有的类 在这个步骤之中就已经 进行了 实例化异常报告器 getSpringFactoriesInstances 它调用的是getSpringFactoriesInstances()方法来获取配置异常类的名称 并实例化所有的异常处理类 SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { //5. 处理args参数 声明并创建一个应用参数对象 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 6.准备环境 创建配置并且绑定环境(通过property sources和profiles等配置文件) ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments); this.configureIgnoreBeanInfo(environment); // 7.创建banner的打印类 Spring Boot启动时会打印Banner图片 Banner printedBanner = this.printBanner(environment); //8.创建应用上下文 根据不同的应用类型来创建不同的ApplicationContext.上下文对象 context = this.createApplicationContext(); context.setApplicationStartup(this.applicationStartup); // 准备应用上下文 此方法的主要作用是把.上面已经创建好的对象,传递给prepareContext来准备上下文 例如将环境变量environment对象绑定到.上下文中、配置bean生成器以及资源加载器记录启动日志等操作. this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); //刷新应用上下文 此方法用于解析配置文件,加载bean对象,并且启动内置的web容器等操作 this.refreshContext(context); //应用上下文刷新之后的事件的处理 此版本的源码中 此段代码为空方法 this.afterRefresh(context, applicationArguments); //停止计时监控类 停止此过程第-步中的程序计时器,并统计任务的执行信息 stopWatch.stop(); //输出日志记录执行主类名、时间信息 把相关的记录信息,如类名、时间等信息进行控制台输出 if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } // 发布应用上下文启动完成事件 触发所有SpringApplicationRunListener监听器的started事件方法 listeners.started(context); // 执行所有Runner运行器 执行所有的ApplicationRunner和CommandLineRunner运行器 this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, listeners); throw new IllegalStateException(var10); } try { //发布应用上下文就绪事件 触发所有的SpringApplicationRunListener监听器的running事件 listeners.running(context); // 返回应用上下文对象 return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
无论是spring框架 还是普通的Java对象 , 在初始化过程是都是先根据属性创建对象,然后再对属性赋予默认值. 在spring源码中. 在bean对象的创建的生命周期中通过三级缓存的方式,解决了常见的 普通循环依赖.当代码存在以下情况时 ,无法解决循环依赖的.如
@Service
public class A {
@Autowired
public B b;
public A(B b) {
this.b = b;
}
}
@Service
public class B {
@Autowired
public A a;
public B(A a) {
this.a = a;
}
}
A、B 两个serverice 中的构造器相互依赖.
@Service
public class A {
@Autowired
public B b;
public A(B b) {
this.b = b;
}
@Async
public void m1(){
}
}
A service中有 @Async注解修饰的方法
@Service
@Scope("prototype")
public class A {
@Autowired
public B b;
public A(B b) {
this.b = b;
}
}
A service中 的作用域范围是 prototype
出现这些情况的解决方法是在循环依赖的类上加一个@Lazy注解,表示延迟加载.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。