三大框架之--Spring 第一章 概述 第二章与IOC

1、 Spring概述

Spring 的主要作用就是为代码“解耦”,降低代码间的耦合度。

根据功能的不同,可以将一个系统中的代码分为主业务逻辑与系统级业务逻辑两类。它
们各自具有鲜明的特点:主业务代码间逻辑联系紧密,有具体的专业业务应用场景,复用性
相对较低;系统级业务相对功能独立,没有具体的专业业务应用场景,主要是为主业务提供
系统级服务,如日志、安全、事务等,复用性强。

Spring 根据代码的功能特点,将降低耦合度的方式分为了两类:IoC 与 AOP。IoC 使得主
业务在相互调用过程中,不用再自己维护关系了,即不用再自己创建要使用的对象了。而是
由 Spring 容器统一管理,自动“注入”。而 AOP 使得系统级服务得到了最大复用,且不用再
由程序员手工将系统级服务“混杂”到主业务逻辑中了,而是由 Spring 容器统一完成“织入”。

1.1Spring体系结构

在这里插入图片描述
Spring 由 20 多个模块组成,它们可以分为数据访问/集成(Data Access/Integration)、
Web、面向切面编程(AOP, Aspects)、应用服务器设备管理(Instrumentation)、消息发送
(Messaging)、核心容器(Core Container)和测试(Test)。

1.2 Spring的特点

1、非侵入式
所谓非侵入式是指,Spring 框架的 API 不会在业务逻辑上出现,即业务逻辑是 POJO。由
于业务逻辑中没有 Spring 的 API,所以业务逻辑可以从 Spring 框架快速的移植到其他框架,
即与环境无关。

2、容器
Spring 作为一个容器,可以管理对象的生命周期、对象与对象之间的依赖关系。可以通
过配置文件,来定义对象,以及设置与其他对象的依赖关系。

3、IoC

控制反转(Inversion of Control),即创建被调用者的实例不是由调用者完成,而是由
Spring 容器完成,并注入调用者。

当应用了 IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象
自己创建或者查找依赖对象。即,不是对象从容器中查找依赖,而是容器在对象初始化时不
等对象请求就主动将依赖传递给它。

4、AOP
面向切面编程(AOP,Aspect Orient Programming),是一种编程思想,是面向对象编程
OOP 的补充。很多框架都实现了对 AOP 编程思想的实现。Spring 也提供了面向切面编程的
丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如日志和事务管理)进行开发。
应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责其它的系统级
关注点,例如日志或事务支持。
我们可以把日志、安全、事务管理等服务理解成一个“切面”,那么以前这些服务一直
是直接写在业务逻辑的代码当中的,这有两点不好:首先业务逻辑不纯净;其次这些服务被
很多业务逻辑反复使用,完全可以剥离出来做到复用。那么 AOP 就是这些问题的解决方案,
可以把这些服务剥离出来形成一个“切面”,以期复用,然后将“切面”动态的“织入”到
业务逻辑中,让业务逻辑能够享受到此“切面”的服务。

AOP面向切面编程比喻:
将主业务当成一本书,切面是另外一种服务与书无关,类似于书签,插入到需要插入的位置,不影响主业务的运行。“书签”提供日志、安全、事务管理。AOP是动态的过程

2、Spring与IoC

控制反转(IOC,Inversion of Control),是一个概念,是一种思想。指将传统上由程序代

码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对
象控制权的转移,从程序代码本身反转到了外部容器。
IoC 是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现方式有两种
依赖注入和依赖查找。依赖注入方式应用更为广泛。
依赖查找:Dependency Lookup,DL,容器提供回调接口和上下文环境给组件,程序代
码则需要提供具体的查找方式。比较典型的是依赖于 JNDI 系统的查找。
依赖注入:Dependency Injection,DI,程序代码不做定位查询,这些工作由容器自行完
成。
依赖注入 DI 是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建
被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。
Spring 的依赖注入对调用者与被调用者几乎没有任何要求,完全支持 POJO 之间依赖关
系的管理。
依赖注入是目前最优秀的解耦方式。依赖注入让 Spring 的 Bean 之间以配置文件的方式
组织在一起,而不是以硬编码的方式耦合在一起的。

2.1 导入jar包

Spring开发的四个基本包
在这里插入图片描述
创建xml配置文件
在这里插入图片描述并在windows->preference->xml catalog里添加 spring-beans.xsd约束文件
:用于定义一个实例对象。一个实例对应一个 bean 元素。
id:该属性是 Bean 实例的唯一标识,程序通过 id 属性访问 Bean,Bean 与 Bean 间的依
赖关系也是通过 id 属性关联的。
class:指定该 Bean 所属的类,注意这里只能是类,不能是接口。

如:bean id=“myService” class=“com.bjpowernode.service.SomeServiceImpl”/>
其实相当于SomeServiceImpl myService = new myService();一句话

2.2ApplicationContext 接口容器

两种方法,xml配置文件路径与写法都不同
01-primary
定义接口

package com.bjpowernode.service;

public interface ISomeService {
	void doSome();
}

定义实现类

package com.bjpowernode.service;

public class SomeServiceImpl implements ISomeService {

	@Override
	public void doSome() {
		System.out.println("执行doSome()方法");

	}

}

xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 注册Service 
    	SomeServiceImpl myService = new myService();
    -->
    <bean id="myService" class="com.bjpowernode.service.SomeServiceImpl"/>

</beans>

MyTest

public class MyTest {
	
	@Test
	public void test01() {
		
		ISomeService service = new SomeServiceImpl();
		service.doSome();

	}
	
	@Test
	public void test02() {
		
		//创建容器对象,加载Spring配置文件
		//会从类路径src下查找配置文件
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		ISomeService service = (ISomeService) ac.getBean("myService");
		
		service.doSome();
		
	}
	
	@Test
	public void test03() {
		
		//创建容器对象,加载Spring配置文件
		//会从当前文件系统的盘根目录下查找配置文件
		ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");
		ISomeService service = (ISomeService) ac.getBean("myService");
		
		service.doSome();
		
	}
}

BeanFactory容器及二者区别

01-primary
ApplicationContext与BeanFactory容器的区别:
两个容器对于Bean的创建时机不同。
1)ApplicationContext容器在进行初始化时,会将其中的所有Bean(对象)进行创建
缺点:占用系统资源(内存、CPU等) 优点:响应速度块

2)BeanFactory容器中的对象,在容器初始化时并不会被创建,而是在真正获取该对象时才被创建
优缺点正好与之相反。

@Test
	public void test04() {
		
		//创建BeanFactory容器 好像是方法g
		//这里注意配置文件还得在类目录src下
		BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
		
		ISomeService service = (ISomeService) bf.getBean("myService");
		
		service.doSome();
		
	}	

一般使用ApplicationContext

2.3 Bean默认装配

代码通过 getBean()方式从容器获取指定的 Bean 实例,容器首先会调用 Bean 类的无参
构造器,创建空值的实例对象。

实现类 分别测试无参和有参构造
02-beanAssemble package com.bjpowernode.ba01;

package com.bjpowernode.ba01;

public class SomeServiceImpl implements ISomeService {

	private int a;
	
	
	
	  public SomeServiceImpl() 
	  { System.out.println("执行无参构造器"); }
	 

		/*
		 * public SomeServiceImpl(int a) { this.a = a; }
		 */
	
	@Override
	public void doSome() {
		System.out.println("执行doSome()方法");

	}

}

容器

package com.bjpowernode.ba01;

public class MyTest {
		
	@Test
	public void test01() {
		
		String resource = "com/bjpowernode/ba01/applicationContext.xml";
		ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
		ISomeService service = (ISomeService) ac.getBean("myService");
		
		service.doSome();
		
	}
	
	
}

底层反射调用的是无参构造器new instance 如果只写有参构造会屏蔽掉无参构造 导致初始化失败

2.4 使用 Spring 的动态工厂 Bean

02-beanAssemble package com.bjpowernode.ba02
实现类

public class SomeServiceImpl implements ISomeService {

	private int a;
	
	  public SomeServiceImpl() 
	  { System.out.println("执行无参构造器"); }
	
	@Override
	public void doSome() {
		System.out.println("执行doSome()方法");

	}

}

工厂

package com.bjpowernode.ba02;

public class ServiceFactory {
	
	public ISomeService getSomeService() {
		return new SomeServiceImpl();
	}
}

配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 注册动态工厂  -->
    <bean id="factory" class="com.bjpowernode.ba02.ServiceFactory"/>

    <!-- 注册Service  -->
    <bean id="myService" factory-bean="factory" factory-method="getSomeService"/>
</beans>

测试

@Test
public void test02() {
	
	String resource = "com/bjpowernode/ba02/applicationContext.xml";
	ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
	//先获取工厂 从service里通过工厂方法获取SomeServiceImpl
	ISomeService service = (ISomeService)ac.getBean("myService");
	service.doSome();
	
}

2.5 容器中Bean的作用域

当通过 Spring 容器创建一个 Bean 实例时,不仅可以完成 Bean 的实例化,还可以通过
scope 属性,为 Bean 指定特定的作用域。Spring 支持 5 种作用域。

(1)**singleton:单例模式。即在整个 Spring 容器中,使用 singleton 定义的 Bean 将是单例的,
只有一个实例。默认为单态的。
(2)prototype:原型模式。即每次使用 getBean 方法获取的同一个的实例都是一个
新的实例。
(3)request:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例。
(4)session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 实例。
(5)global session:每个全局的 HTTP session 对应一个 Bean 实例。典型情况下,仅在使用
portlet 集群时有效,多个 Web 应用共享一个 session。一般应用中,global-session 与 session
是等同的。
注意:
(1)对于 scope 的值 request、session 与 global session,只有在 Web 应用中使用 Spring 时,
该作用域才有效。
(2)对于 scope 为 singleton 的单例模式,该 Bean 是在容器被创建时即被装配好了。
(3)对于 scope 为 prototype 的原型模式,Bean 实例是在代码中使用该 Bean 实例时才进行
装配的。

在这里插入图片描述

在这里插入图片描述
前者为true 执行一次无参构造 创建一个对象
后者为false 执行两次无参构造 创建两个对象

2.6 Bean后处理器

Bean 后处理器是一种特殊的 Bean,容器中所有的 Bean 在初始化时,均会自动执行该
类的两个方法。由于该 Bean 是由其它 Bean 自动调用执行,不是程序员手工调用,故此 Bean
无须 id 属性。
需要做的是,在 Bean 后处理器类方法中,只要对 Bean 类与 Bean 类中的方法进行判断,
就可实现对指定的 Bean 的指定方法进行功能扩展与增强。方法返回的 Bean 对象,即是增
过的对象。
代码中需要自定义 Bean 后处理器类。该类就是实现了接口 BeanPostProcessor 的类。该
接口中包含两个方法,分别在目标 Bean 初始化完毕之前与之后执行。它们的返回值为:功
能被扩展或增强后的 Bean 对象。
Bean 初始化完毕有一个标志:一个方法将被执行。即当该方法被执行时,表示该 Bean
被初始化完毕。所以 Bean 后处理器中两个方法的执行,是在这个方法之前之后执行。这个
方法在后面将会讲到。
public Object postProcessBeforeInitialization(Object bean, String beanId)
throws BeansException
该方法会在目标 Bean 初始化完毕之前由容器自动调用。
public Object postProcessAfterInitialization(Object bean, String beanId) throws BeansException
该方法会在目标 Bean 初始化完毕之后由容器自动调用。
它们的参数是:第一个参数是系统即将初始化的 Bean 实例,第二个参数是该 Bean 实
例的 id 属性值。若 Bean 没有 id 就是 name 属性值。
02-beanAssemble package com.bjpowernode.ba05;

示例:
接口:

package com.bjpowernode.ba05;

public interface ISomeService {
	String doSome();
	
	String doOther();
}

实现类

package com.bjpowernode.ba05;

public class SomeServiceImpl implements ISomeService {
	
	@Override
	public String doSome() {
		System.out.println("执行doSome()方法");
		return "abcde";

	}

	@Override
	public String doOther() {
		
		System.out.println("执行doOther()方法");
		return "fghig";
	}

}

Bean后处理器 在after里使用proxy动态代理
实现了只有service1中的doSome实现增强

package com.bjpowernode.ba05;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {
	
	//bean:表示当前正在进行初始化的Bean对象
	//beanName:表示当前正在进行初始化的Bean对象的id
	
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("执行----before---()方法");
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(final Object bean, String beanName) throws BeansException {
		System.out.println("执行----after---()方法");
		if ("myService".equals(beanName)) {
			Object obj = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(),
					new InvocationHandler() {

						@Override
						public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
							Object invoke = method.invoke(bean, args);
							if ("doSome".equals(method.getName())) {						
								return ((String) invoke).toUpperCase();
							}
							return invoke;
						}

					});
			return obj;
		}
		
		return bean;
	}


}

测试类

public class MyTest {
		
	@Test
	public void test01() {
		
		String resource = "com/bjpowernode/ba05/applicationContext.xml";
		ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
			
		ISomeService service = (ISomeService)ac.getBean("myService");
		System.out.println(service.doSome());
		System.out.println(service.doOther());
		
		System.out.println("----------------");
		
		ISomeService service2 = (ISomeService)ac.getBean("myService2");
		System.out.println(service2.doSome());
		System.out.println(service2.doOther());
	}
	
	
}

配置文件
省略了约束文件

<bean id="myService" class="com.bjpowernode.ba05.SomeServiceImpl"/>
    <bean id="myService2" class="com.bjpowernode.ba05.SomeServiceImpl"/>
    

结果:
执行----before—()方法
执行----after—()方法
执行----before—()方法
执行----after—()方法
执行doSome()方法
ABCDE
执行doOther()方法
fghig
----------------‘
执行doSome()方法
abcde
执行doOther()方法
fghig

2.7 定制Bean的生命始末

可以为 Bean 定制初始化后的生命行为,也可以为 Bean 定制销毁前的生命行为。
对于销毁方法的执行,有两个条件:
1)当前的Bean需要时singleton的(默认)
2)要手动关闭容器
02-beanAssemble package com.bjpowernode.ba07;
实现类:

package com.bjpowernode.ba07;

public class SomeServiceImpl implements ISomeService {

	
	  public SomeServiceImpl() 
	  { System.out.println("执行无参构造器"); }
	 

	@Override
	public void doSome() {
		System.out.println("执行doSome()方法");

	}
	
	public void setUp() {
		System.out.println("生命起始");
	}

	public void tearDown() {
		System.out.println("销毁之前");
	}
}

注册文件 在末尾添加生命始末方法的注册

<bean id="myService" class="com.bjpowernode.ba07.SomeServiceImpl"
    		init-method="setUp" destroy-method="tearDown"/>

测试结果:

package com.bjpowernode.ba07;

public class MyTest {
		
	@Test
	public void test01() {
		
		//创建容器对象,加载Spring配置文件
		//会从类路径src下查找配置文件
		//底层反射调用的是无参构造器new instance 如果写有参构造会屏蔽掉无参构造 导致初始化失败
		
		String resource = "com/bjpowernode/ba07/applicationContext.xml";
		ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
		ISomeService service = (ISomeService) ac.getBean("myService");
		
		service.doSome();
		//关闭
		((ClassPathXmlApplicationContext)ac).close();
		
	}
}

2.8 Bean的生命周期

Step1:调用无参构造器,创建实例对象。
Step2:调用参数的 setter,为属性注入值。
Step3:若Bean实现了BeanNameAware接口,则会执行接口方法setBeanName(String beanId),
使 Bean 类可以获取其在容器中的 id 名称。
Step4:若 Bean 实现了 BeanFactoryAware 接口,则执行接口方法 setBeanFactory(BeanFactory
factory),使 Bean 类可以获取到 BeanFactory 对象。
Step5 : 若 定 义 并 注 册 了 Bean 后 处 理 器 BeanPostProcessor , 则 执 行 接 口 方 法
postProcessBeforeInitialization()。
Step6:若 Bean 实现了 InitializingBean 接口,则执行接口方法 afterPropertiesSet ()。该方法
在 Bean 的所有属性的 set 方法执行完毕后执行,是 Bean 初始化结束的标志,即 Bean 实例
化结束。
Step7:若设置了 init-method 方法,则执行。
Step8 : 若 定 义 并 注 册 了 Bean 后 处 理 器 BeanPostProcessor , 则 执 行 接 口 方 法
postProcessAfterInitialization()。
Step9:执行业务方法。
Step10:若 Bean 实现了 DisposableBean 接口,则执行接口方法 destroy()。
Step11:若设置了 destroy-method 方法,则执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值