spring 核心知识

什么是spring

  • spring是一个轻量级的IOC和AOP容器框架。是为JAVA应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。

主要模块

Spring AOP : AOP服务
Spring Core : 核心库类,提供IOC服务
Spring Context : 提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等)
Spring DAO : 对JDBC的抽象 ,简化了数据库访问异常的处理
Spring ORM : 对现有的ORM框架的支持
Spring Web : 提供了基本的面向Web的综合特性
Spring MVC : 提供面向Web应用的Model-View-Controller实现

spring IOC

  • Inversion of Control 控制反转
  • 所谓 IOC ,就是由 Spring IOC 容器来负责对象的生命周期和对象之间的关系。
  • Spring 启动时读取应用程序提供的 Bean 配置信息,并在 Spring 容器中生成一份相应的 Bean 配置注册表,然后根据这张注册表实例化 Bean,装配好 Bean 之间的依赖关系,为上层应用提供准备就绪的运行环境。其中 Bean 缓存池为 HashMap 实现。

BeanFactory

  • 是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;
  • 定义了允许在运行期间向容器注册单实例 Bean 的方法;对于单实例( singleton)的 Bean 来说,BeanFactory 会缓存 Bean 实例,所以第二次使用 getBean() 获取 Bean 时将直接从IoC 容器的缓存中获取 Bean 实例。
  • 在初始化 BeanFactory 时,必须为其提供一种日志框架,比如使用 Log4J, 即在类路径下提供 Log4J 配置文件,这样启动 Spring 容器才不会报错。

ApplicationContext

  • 应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能;

    • ClassPathXmlApplicationContext:默认从类路径加载配置文件

    • FileSystemXmlApplicationContext:默认从文件系统中装载配置文件

    • 国际化(MessageSource):为应用提供 i18n 国际化消息访问的功能;

    • 访问资源,如URL和文件(ResourceLoader)

    • 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层

    • 消息发送、响应机制(ApplicationEventPublisher)让容器拥有发布应用上下文事件的功能,包括容器启动事件、关闭事件等。

    • AOP(拦截器)

  • ClassPathXmlApplicationContext

    • 简单的用 ApplicationContext 做测试的话 , 获得 Spring 中定义的 Bean 实例(对象) 可以用:
      ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    • 如果是两个以上 , 可以使用字符串数组 :
      ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml","SpringTest.xml"});
    • 或者可以使用通配符:
      ApplicationContext context = new ClassPathXmlApplicationContext("classpath:/*.xml");
      对于 ClassPathXmlApplicationContext 的使用:
  • classpath: 前缀是可加可不加的 , 默认就是指项目的 classpath 路径下面。
    如果要使用绝对路径 , 需要加上 file: , 前缀表示这是绝对路径。

spingboot源码指的classpath

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { 
    "classpath:/META-INF/resources/", 
    "classpath:/resources/", 
    "classpath:/static/", 
    "classpath:/public/" }; 
  • 对于 FileSystemXmlApplicationContext 的使用:

    • 没有盘符的是项目工作路径 , 即项目的根目录。
    • 有盘符表示的是文件绝对路径 ,file: 可加可不加。
    • 如果要使用 classpath 路径 , 需要前缀 classpath:。
  • ApplicationEventPublisher

  • ApplicationContext 通过 ApplicationEvent 类和 ApplicationListener 接口进行事件处理。 如果将实现 ApplicationListener 接口的 bean 注入到上下文中,则每次使用 ApplicationContext 发布 ApplicationEvent 时,都会通知该 bean。本质上,这是标准的观察者设计模式。

  • 事件定义

public class UserRegisterEvent extends ApplicationEvent{
    public UserRegisterEvent(String name) { //name即source
        super(name);
    }
}
  • 事件发布者
@Service
public class UserService implements ApplicationEventPublisherAware {
    private ApplicationEventPublisher applicationEventPublisher;
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
    public void register(String name) {
        System.out.println("用户:" + name + " 已注册!");
        applicationEventPublisher.publishEvent(new UserRegisterEvent(name));
    }
}
  • 事件订阅者
@Service
public class EmailService implements ApplicationListener<UserRegisterEvent> {
    @Override
    public void onApplicationEvent(UserRegisterEvent userRegisterEvent) {
        System.out.println("邮件服务接到通知,给 " + userRegisterEvent.getSource() + " 发送邮件...");
    }
}
  • WebApplication 体系架构
    • WebApplicationContext 是专门为 Web 应用准备的,它允许从相对于 Web 根目录的路径中装载配置文件完成初始化工作。从 WebApplicationContext 中可以获得ServletContext 的引用,整个 Web 应用上下文对象将作为属性放置到 ServletContext 中,以便 Web 应用环境可以访问 Spring 应用上下文。


      image.png

BeanFactory和ApplicationContext

两者装载bean的区别:
BeanFactory:
BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化;

ApplicationContext:
ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化;

各自优点:

  • 延迟实例化的优点:(BeanFactory)
    应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势;

  • 不延迟实例化的优点: (ApplicationContext)

  1. 所有的Bean在启动的时候都加载,系统运行的速度快;

  2. 在启动的时候所有的Bean都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题

  3. 建议web应用,在启动的时候就把所有的Bean都加载了。(把费时的操作放到系统启动中完成)

Spring Bean 作用域(用于判断bean的个数)

  • singleton(单例)、prototype(原型)、request、session 和 global session


    image.png
  • singleton:单例模式(多线程下不安全,此为spring默认的生命周期)

    • singleton:单例模式,Spring IoC 容器中只会存在一个共享的 Bean 实例,无论有多少个Bean 引用它,始终指向同一对象。该模式在多线程下是不安全的。Singleton 作用域是Spring 中的缺省作用域,也可以显示的将 Bean 定义为 singleton 模式,配置为:
      <bean id="userDao" class="com.ioc.UserDaoImpl" scope="singleton"/>
  • prototype:原型模式(每次使用时创建)

    • 每次通过 Spring 容器获取 prototype 定义的 bean 时,容器都将创建一个新的 Bean 实例,每个 Bean 实例都有自己的属性和状态,而 singleton 全局只有一个对象。根据经验,对有状态的bean使用prototype作用域,而对无状态的bean使用singleton作用域。
  • Request:一次 request 一个实例

    • request:在一次 Http 请求中,容器会返回该 Bean 的同一实例。而对不同的 Http 请求则会产生新的 Bean,而且该 bean 仅在当前 Http Request 内有效,当前 Http 请求结束,该 bean实例也将会被销毁。
      <bean id="loginAction" class="com.cnblogs.Login" scope="request"/>
  • session

    • 在一次 Http Session 中,容器会返回该 Bean 的同一实例。而对不同的 Session 请求则会创建新的实例,该 bean 实例仅在当前 Session 内有效。同 Http 请求相同,每一次session 请求创建新的实例,而不同的实例之间不共享属性,且实例仅在自己的 session 请求内有效,请求结束,则实例将被销毁。
  • global Session

    • global Session:在一个全局的 Http Session 中,容器会返回该 Bean 的同一个实例,仅在使用 portlet context 时有效。

Spring Bean 生命周期

  1. Spring对Bean进行实例化(相当于程序中的new Xx())

  2. Spring将值和Bean的引用注入进Bean对应的属性中,利用IOC

  3. 如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()方法(实现BeanNameAware清主要是为了通过Bean的引用来获得Bean的ID,一般业务中是很少有用到Bean的ID的)

  4. 如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanDactory(BeanFactory bf)方法并把BeanFactory容器实例作为参数传入。(实现BeanFactoryAware 主要目的是为了获取Spring容器,如Bean通过Spring容器发布事件等)

  5. 如果Bean实现了ApplicationContextAware接口,Spring容器将调用setApplicationContext(ApplicationContext ctx)方法,把应用上下文作为参数传入.(作用与BeanFactory类似都是为了获取Spring容器,不同的是Spring容器在调用setApplicationContext方法时会把它自己作为setApplicationContext 的参数传入,而Spring容器在调用setBeanDactory前需要程序员自己指定(注入)setBeanDactory里的参数BeanFactory )

  6. 如果Bean实现了BeanPostProcess接口,Spring将调用它们的postProcessBeforeInitialization(预初始化)方法(作用是在Bean实例创建成功后对进行增强处理,如对Bean进行修改,(增加某个功能,这个很重要,AOP就是在这里实现的)

  7. 如果Bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet方法,作用与在配置文件中对Bean使用init-method声明初始化的作用一样,都是在Bean的全部属性设置成功后执行的初始化方法。

  8. 如果Bean实现了BeanPostProcess接口,Spring将调用它们的postProcessAfterInitialization(后初始化)方法(作用与6的一样,只不过6是在Bean初始化前执行的,而这个是在Bean初始化后执行的,时机不同 ) 这个时候已经再被使用了

  9. 经过以上的工作后,Bean将一直驻留在应用上下文中给应用使用,直到应用上下文被销毁

  10. 如果Bean实现了DispostbleBean接口,Spring将调用它的destory方法,作用与在配置文件中对Bean使用destory-method属性的作用一样,都是在Bean实例销毁前执行的方法。

  • 主要逻辑都在doCreate()方法中,逻辑很清晰,就是顺序调用以下三个方法,这三个方法与三个生命周期阶段一一对应,非常重要,在后续扩展接口分析中也会涉及。
    • createBeanInstance() -> 实例化
    • populateBean() -> 属性赋值
    • initializeBean() -> 初始化
// 忽略了无关代码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (instanceWrapper == null) {
       // 实例化阶段!
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
       // 属性赋值阶段!
      populateBean(beanName, mbd, instanceWrapper);
       // 初始化阶段!
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }

   
   }

当容器关闭时调用bean的销毁方法

Spring Bean 依赖注入

● 理解基于构造函数的依赖注入

/*带参数,方便利用构造器进行注入*/ 
 public CatDaoImpl(String message){ 
 this. message = message; 
 } 
<bean id="CatDaoImpl" class="com.CatDaoImpl"> 
<constructor-arg value=" message "></constructor-arg> 
</bean>

● 理解基于设置函数的依赖注入

public class Id { 
 private int id; 
 public int getId() { return id; } 
 public void setId(int id) { this.id = id; } 
} 
<bean id="id" class="com.id "> <property name="id" value="123"></property> </bean>

● 基于自动装配的依赖注入(配置文件里不用写依赖关系了,有相应的方法就行)
byType(类型模式),byName(名称模式)、constructor(构造函数模式)

● 基于注解的依赖注入(方法都省略了)
@Autowired @Resource

Spring AOP

AOP 把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
1、切面(aspect):一般就是一个类。切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强!
2、横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。 (相对于核心关注点来说的)
3、连接点(joinpoint):连接点是在应用执行过程中能够插入切面(Aspect)的一个点。这些点可以是调用方法时、甚至修改一个字段时。虚的概念
4、切入点(pointcut):在哪些类,哪些方法上切入(where)
5、通知(advice):在方法执行的什么实际(when:方法前/方法后/方法前后)做什么(what:增强的功能),通知分为前置、后置、异常、最终、环绕通知五类。
6、目标对象:代理的目标对象。
7、织入(weave):把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)
8、引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。

  • 连接点和切入点的理解
    • 连接点:连接点是一个虚拟的概念,可以理解为所有满足切点扫描条件的所有的时机。

    • 具体举个例子:比如开车经过一条高速公路,这条高速公路上有很多个出口(连接点),但是我们不会每个出口都会出去,只会选择我们需要的那个出口(切点)开出去。

    • 简单可以理解为,每个出口都是连接点,但是我们使用的那个出口才是切点。每个应用有多个位置适合织入通知,这些位置都是连接点。但是只有我们选择的那个具体的位置才是切点。

@Aspect
public class TransactionDemo {
   @Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))")
   public void point(){
   }

   @Before(value="point()")
   public void before(){
     System.out.println("transaction begin");
   }

   @AfterReturning(value = "point()")
   public void after(){
     System.out.println("transaction commit");
   }

   @Around("point()")
   public void around(ProceedingJoinPoint joinPoint) throws Throwable{
     System.out.println("transaction begin");
     joinPoint.proceed();
     System.out.println("transaction commit");
 } }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342