spring 为什么可以一统江湖

学习的路线设定

  • 了解有多少种方式添加对象到容器中
  • 再从spring对一个类的处理的源码开始解析spring的原理

Spring配置有两种,详细法就可以参考一下Spring的使用教程。

xml配置与注解方式配置。其他本质是一样的。

  • xml
  • 配置类上加Configuration

扫描加载bean的规则有,这些不是很重要.

  • @bean
	<bean id="person" class="com.enjoy.cap1.Person">
<property name="name" value="wolf"></property>
<property name="age" value="19"></property>
</bean>
或在Configuration类中使用,现在的spring boot都是用@Configuration方式的 @Configuration
@Import(value = { Dog.class })
public class Cap6MainConfig {}
  • @@Component与@ComponentScan(value = "bgy.bean")
    @Component
public class Dog{}
  • @@Import(bgy.beanout.Fly.class) 单独加入
@Configuration
@Import(value = { Dog.class })
public class Cap6MainConfig {}
  • 实现ImportSelector
public class MyImportSelector implements ImportSelector{
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata){
//返回全类名的bean
return new String[]{"com.enjoy.cap6.bean.Fish","com.enjoy.cap6.bean.Tiger"};
}
} //把MyImportSelector当成bean导入
@Import(value = {ImportSelector.class})
  • 使用FactoryBean
public class JamesFactoryBean implements FactoryBean<Monkey>{

	@Override
public Monkey getObject() throws Exception {
// TODO Auto-generated method stub
return new Monkey();
} @Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Monkey.class;
} @Override
public boolean isSingleton() {
return true;
}
}
  • 使用HdkImportBeanDefinitionRegistrar
public class HdkImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	/*
*AnnotationMetadata:当前类的注解信息
*BeanDefinitionRegistry:BeanDefinition注册类
* 把所有需要添加到容器中的bean加入;
* @Scope
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean bean1 = registry.containsBeanDefinition("com.enjoy.cap6.bean.Dog");
boolean bean2 = registry.containsBeanDefinition("com.enjoy.cap6.bean.Cat");
//如果Dog和Cat同时存在于我们IOC容器中,那么创建Pig类, 加入到容器
//对于我们要注册的bean, 给bean进行封装,
if(bean1 && bean2){
RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class);
registry.registerBeanDefinition("pig", beanDefinition);
}
} }
  • BeanDefinitionRegistryPostProcessor
public class JamesBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor{

	@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("JamesBeanDefinitionProcessor..postProcessBeanFactory(),Bean的数量"+beanFactory.getBeanDefinitionCount());
} @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("amesBeanDefinition.postProcessBeanDefinitionRegistry()...bean的数量"+registry.getBeanDefinitionCount());
//RootBeanDefinition rbd = new RootBeanDefinition(Moon.class);
AbstractBeanDefinition rbd = BeanDefinitionBuilder.rootBeanDefinition(Moon.class).getBeanDefinition();//注册一个beandefinition
registry.registerBeanDefinition("hello", rbd);
} }

Condition 条件加载,在spring boot中使用比较广泛,用来过滤加载到IOC容器中的bean

public class WinCondition implements Condition{

	/*
*ConditionContext: 判断条件可以使用的上下文(环境)
*AnnotatedTypeMetadata: 注解的信息
*
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO 是否为WINDOW系统
//能获取到IOC容器正在使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取当前环境变量(包括我们操作系统是WIN还是LINUX??)
Environment environment = context.getEnvironment();
String os_name = environment.getProperty("os.name");
if(os_name.contains("Windows")){
return true;
}
return false;
} }

小结:

spring 源码解析

从加载容器开始

      ApplicationContext applicationContext=new AnnotationConfigApplicationContext(myconfig.class);
// ApplicationContext applicationContext=new ClassPathXmlApplicationContext("beans.xml");

上下文抽象类,此设计用的是模板方法设计模式, 在refresh里 固定好加载时的方法调用顺序。

 public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();//加载 bean的配置定义
this.prepareBeanFactory(beanFactory); try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);//如果有配置类则添加配置类处理器,并将优先级排为最高
this.registerBeanPostProcessors(beanFactory);//注册其他的处理器,并设置好处理顺序。
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);//注册所有注入进来的bean实例到容器中
this.finishRefresh();
} catch (BeansException var9) {
if(this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
} this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
} }
}

BeanPostProcessors

@Component
////每个对象创建时都会执行
public class MyBeanPostProcessor implements BeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//返回一个的对象(传过来的对象)
//在初始化方法调用之前进行后置处理工作,
//什么时候调用它: 对象的构造方法之后,init-method=init之前调用
System.out.println("postProcessBeforeInitialization...."+beanName+"..."+bean);
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//init-method=init之后调用
System.out.println("postProcessAfterInitialization...."+beanName+"..."+bean);
return bean;
}
}

ApplicationContextAware

public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext var1) throws BeansException;
}

bean中

   public void setApplicationContext(ApplicationContext applicationContext) {
if(this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {
this.webApplicationContext = (WebApplicationContext)applicationContext;
this.webApplicationContextInjected = true;
} }

spring 应用组件扩展

spring mvc 原理

首先从问题开始

  • 请求路径是如何定位到一个servlet的?
  • 请求如何找到MVC中的@RequestMapping("view”)方法呢?

  • 在mvc的web.xml找到servlet的配置。

    spring 为什么可以一统江湖-LMLPHP

  • 再看看DispatcherServlet是个什么玩意

    spring 为什么可以一统江湖-LMLPHP

容器类将加载@Controller的类型的实例加载到容器中。@Controller其实就是一个@Component

spring 为什么可以一统江湖-LMLPHP

dispatcherServlet将@Controller的bean与RequestMapping的value做映射HandlerMappings

  • initStrategies 初始化相关信息

    spring 为什么可以一统江湖-LMLPHP

initHandlerMappings

spring 为什么可以一统江湖-LMLPHP

doService()

  • 看看调用堆

    spring 为什么可以一统江湖-LMLPHP

spring 为什么可以一统江湖-LMLPHP

spring 为什么可以一统江湖-LMLPHP

    protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
AnnotationMethodHandlerAdapter.ServletHandlerMethodResolver methodResolver = this.getMethodResolver(handler);
Method handlerMethod = methodResolver.resolveHandlerMethod(request);//获取到controller中的方法
AnnotationMethodHandlerAdapter.ServletHandlerMethodInvoker methodInvoker = new AnnotationMethodHandlerAdapter.ServletHandlerMethodInvoker(methodResolver);
ServletWebRequest webRequest = new ServletWebRequest(request, response);
ExtendedModelMap implicitModel = new BindingAwareModelMap();
Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
methodInvoker.updateModelAttributes(handler, mav != null?mav.getModel():null, implicitModel, webRequest);
return mav;
}

1 找到处理类controller

spring 为什么可以一统江湖-LMLPHP

2 找到处理方法进行反射

spring 为什么可以一统江湖-LMLPHP

3 调用到requestmapping的方法

spring 为什么可以一统江湖-LMLPHP

设计模式发现

spring 为什么可以一统江湖-LMLPHP

可适配类型

spring 为什么可以一统江湖-LMLPHP

下面用实现controller接口的方式实现请求处理类。这种方式 使用的是SimpleControllerHandlerAdapter这种适配器,servlet的话就会使用SimpleServletHandlerAdapter

spring 为什么可以一统江湖-LMLPHP

@Component
@RequestMapping("index")
public class TestController implements org.springframework.web.servlet.mvc.Controller { @Override
public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
return new ModelAndView("index.jsp");
}
}

总结

spring aop

通知方法

  • 前置通知: logStart(),在目标方法(div)运行之前运行 (@Before)
  • 后置通知:logEnd(), 在目标方法(div)运行结束之后运行,无论正常或异常结束 (@After)
  • 返回通知:logReturn, 在目标方法(div)正常返回之后运行 (@AfterReturning)
  • 异常通知:logException, 在目标方法(div)出现异常后运行(@AfterThrowing)
  • 环绕通知:@Around以上没写,动态代理, 手动执行目标方法运行joinPoint.procced(),最底层通知,

原理

  • 通过@Pointcut("execution(public int com.enjoy.cap10.aop.Calculator.*(..))") 配置找到要代理拦截的方法。

  • DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice 生成拦截链加到list遍历调用。

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
List<Object> interceptorList = new ArrayList(config.getAdvisors().length);
Class<?> actualClass = targetClass != null?targetClass:method.getDeclaringClass();
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
Advisor[] var8 = config.getAdvisors();
int var9 = var8.length; for(int var10 = 0; var10 < var9; ++var10) {
Advisor advisor = var8[var10];
MethodInterceptor[] interceptors;
if(advisor instanceof PointcutAdvisor) {
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor;
if(config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if(MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if(mm.isRuntime()) {
MethodInterceptor[] var15 = interceptors;
int var16 = interceptors.length; for(int var17 = 0; var17 < var16; ++var17) {
MethodInterceptor interceptor = var15[var17];
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
} else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
} else if(advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor)advisor;
if(config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
} else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
} return interceptorList;
}
  • 虽然是顺序结构,但是调用执行顺序却是从下面开始的,类似递归算法那样。下往上执行。

    spring 为什么可以一统江湖-LMLPHP

  • 执行拦截器链ReflectiveMethodInvocation.proceed()

   public Object proceed() throws Throwable {
if(this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return this.invokeJoinpoint();
} else {
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if(interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
return dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)?dm.interceptor.invoke(this):this.proceed();
} else {
return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
}
}
}

总结

05-27 11:48