Spring
一.Spring简介
1. Spring是一个开源的轻量级应用框架,目的在于减轻企业级应用程序开发,降低侵入性。
2. Spring提供IOC和AOP功能,可将组件之间的耦合度降到最低,即实现解耦的目的,便于系统日后维护和升级
3. Spring为系统提供了一个整体的解决方案,开发者除了使用其本身的功能外还可以将Spring与第三方架构技术整合应用,可以自由选择采用哪些技术进行开发。Spring的本质就是管理软件中的对象,即创建对象和维护对象之间的关系。
二.Spring特点
轻量级、容器、Ioc、AOP
轻量级(LightWeight)相较与EJB而言,Spring是轻量级容器,不依赖于任何web容器
容器(Container)Spring本身不具备任何功能,仅仅对javaBean进行生命周期和读写管理。
IOC(Inversion of Control)Spring实现的核心是IOC,即控制反转,完全由Spring容器负责维护资源间的依赖关系
AOP(Aspect oriented programming)AOP 框架是Spring框架的子框架,以切面资源模式在不更改源代码的情况下增加新的功能。
三.Spring容器
1. Spring中,任何的java类和JavaBean都被当成Bean处理,这些Bean通过容器管理和使用,
javaBean POJO VO Entity
2. Spring容器实现了IOC和AOP机制,这些机制可以简化bean对象的创建和Bean对象的解耦
3. Spring容器分为Beanfactory和 ApplicationContext
四.Spring容器实例化
可以使用BeanFactory和ApplicationContext来创建Spring容器,一般使用ApplicationContext,因为applicationContext 继承BeanFactory
1. 导入Spring相关jar包
2. 导入applicationContext.xml文件
3. 创建容器
方法1:
ApplicationContextac = new ClassPathXmlApplicationContext(
"applicationContext.xml");
System.out.println(ac);
方法2:
ApplicationContext acc = newFileSystemXmlApplicationContext("src"
+ File.separator +"applicationContext.xml");
System.out.println(acc);
五.Bean实例化
1. 用构造器来实例化
<bean id="person" class="com.xff.Bean.Person"/>
Person p = ac.getBean("person", Person.class);
System.out.println(p);
相当于:
Person p=new Person();
2. 静态工厂方法来实例化
<bean id="calendar4"class="java.util.Calendar"factory-method="getInstance"/>
System.out.println(ac.getBean("calendar4",Calendar.class));
相当于:
Calendar c=Calendar.getInstance();
3. 实例工厂
<beanid="calendar5" class="java.util.GregorianCalendar"/>
<bean id="calendar6" factory-bean="calendar5"factory-method="getTime"/>
System.out.println(ac.getBean("calendar6", Date.class));
相当于:
Calendarc= new GregorianCalendar();
c.getTime();
六.Bean的命名
Bean的名称:在spring容器中,每一个bean都要有名字,id或name (id比name更严格)都不能重复,id和name也不能重复。
七.Bean的作用域
Spring容器在实例化bean时,可以创建以下作用域的Bean对象
Singleton在每一个Spring容器中一个对象只有一个实例
protoType 一个Bean定义多个对象实例
request 在Http请求中是有效,仅限WEB环境
session
global session 全局Httpsession,仅限于protlet的web才有效
八.Bean生命周期(销毁方法和初始化仅适用singlenton的bean,虽然原型也适用,区别在于,singleton bean的生命周期完全由Spring容器管理,而prototype则不是)
1. Bean的定义(xml中定义)
2. Bean的初始化
在Person类中添加init()方法
<bean id="per1" class="com.xff.Bean.Person"scope="prototype" init-method="init"/>
3. Bean的调用(ApplicationContext)
4. Bean销毁
调用bean的destory方法,销毁Spring容器时销毁
如果是singleton,创建容器时就已经初始化;
如果是prototype,调用时初始化
<beanid="per1" class="com.xff.Bean.Person" init-method="init"destroy-method="destory"/>
<beanid="per2" class="com.xff.Bean.Person" init-method="init" scope="prototype" destroy-method="destory"/>
publicstatic void main(String[] args) {
ApplicationContext ac = newClassPathXmlApplicationContext(
"applicationContext.xml");
ac.getBean("per2");
AbstractApplicationContext abap =(AbstractApplicationContext) ac;
abap.close();
}
九.全局初始化和销毁方法
default-init-method="init"
default-destroy-method="destory"
如果单个bean中有单独定义里初始化或销毁方法,会覆盖全局方法
十.延时加载
lazy-init="default" 默认为false 即启动就加载
十一. IOC 控制反转
IOC指程序中对象获取的方式发生了转变,由最初的new方式进行创建,转变由第三方框架创建、注入。第三方框架,一般是通过配置方法指定注入哪一个具体事项,从而降低对象之间的耦合度
IOC按实现方式不同,可以分为依赖注入DI和依赖查找两种。IOC是Spring框架的基础和核心。
DI Dependency Injection 依赖注入,基本原理就是将一起工作具有关系的对象,通过构造方法参数传入建立关系,因此容器的工作就是创建bean时注入那些依赖关系。
IOC是一种实现,而DI是实现IOC的主要技术路径。
十二. DI的两种注入方式
1. Setter注入
通过调用无参构造方法或无参static方法实例化bean以后,调用该bean的setter方法,即可实现setter注入。
<beanid="per4" class="com.xff.Bean.Person">
<propertyname="name" value="Tom"></property>
<propertyname="age" value="14"></property>
</bean>
引用类型:
<beanid="add1" class="com.xff.Bean.Address">
<propertyname="country" value="China"></property>
<propertyname="province" value="JiangSu"></property>
</bean>
<bean id="per5"class="com.xff.Bean.Person">
<propertyname="name" value="Tom"></property>
<propertyname="age" value="14"></property>
<propertyname="address" ref="add1"/>
</bean>
2. 构造器注入
基于调用构造器(带参数构造器)来实现,容器的bean被实例化的时候,根据参数类型执行相应的构造器
<beanid="person2" class="com.xff.bean.Persion">
<constructor-argname="age" value="12"></constructor-arg>
<constructor-argname="name" value="Tom"> </constructor-arg>
<constructor-argname="address" ref="address"></constructor-arg>
</bean>
十三. 自动装配
Spring IOC容器可以自动装配(autowred)互相协作的bean之间的关联关系,autoWired可以针对单个的bean进行设置,autowired可以针对单个bean进行设置,autowired的方便之处在于减少XML的配置,共有5种:
no 禁止使用,默认
byName根据属性名进行装配,检查容器根据名字进行匹配。
byType 如果容器中存在一个与指定属性类型相同的bean,自动匹配该属性,
constructor与bytype方法类似,不同之处在于它用于构造器参数,
autodetect通过bean类来决定constructor还是bytype方法进行自动装配,如果发现默认构造器则使用bytype
十四. 其它类型的注入
1. 注入集合,通过list map set props元素可以定义和设置java中对应类型的list set map 和properties
<beanid="clo" class="com.xff.bean.CollectionUtil">
<propertyname="list">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<propertyname="set">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
<propertyname="map">
<map>
<entrykey="key1">
<value>value1</value>
</entry>
<entrykey="key2" value="value2">
</entry>
</map>
</property>
<propertyname="properties" >
<props>
<propkey="username">Tom</prop>
<propkey="password">123456</prop>
</props>
</property>
</bean>
注入复杂类型:
<propertyname="add">
<list>
<refbean="address"/>
</list>
</property>
2. 通过util注入:
<util:listid="list2">
<value>list1</value>
</util:list>
<util:set id="set1">
<value>sat1</value>
</util:set>
<util:map id="map1">
<entrykey="key1" value="value1"> </entry>
</util:map>
<util:properties id="pro1">
<propkey="username">Jack</prop>
</util:properties>
<util:list id="address2">
<refbean="address"/>
</util:list>
<bean id="clo2"class="com.xff.bean.CollectionUtil">
<propertyname="list" ref="list2"></property>
<propertyname="set" ref="set1"></property>
<propertyname="map" ref="map1"></property>
<propertyname="properties" ref="pro1"></property>
<propertyname="add" ref="address2"></property>
</bean>
3. 注入Spring表达式
Spring引入的一种表达式语言,语法和el很像,这种表达式语言可以用户定义基于XML和注解配置的Bean,注入一个properties文件信息。
<util:propertiesid="pro2" location="classpath:ds.properties"></util:properties>
<bean id="clo3"class="com.xff.bean.CollectionUtil">
<propertyname="properties" ref="pro2"></property>
</bean>
或
<beanid="clo4" class="com.xff.bean.CollectionUtil">
<propertyname="properties">
<props>
<propkey="usr">#{pro2.username}</prop>
<propkey="pwd">#{pro2.password}</prop>
</props>
</property>
</bean>
4. 注入null
<beanid="person4" class="com.xff.bean.Persion">
<propertyname="address" ><null/></property>
</bean>
十五. Aop
面向切面的编程,Aop是Spring框架的重要支持,但不是只有Spring才有AOP的实现,Filter就是典型的例子,简单来说AOP的作用是能在方法执行的前后切入相应的代码,并且不需要改变源文件本身(代理模式)
AOP主要用于处理共同的逻辑,例如日志记录,安全控制,事务处理,异常处理等。Aop可以将这些共同的逻辑从普通的业务逻辑代码中分离出来,这样日后修改这些逻辑的时候就不会影响普通业务逻辑代码。
利用Aop对业务逻辑的各个部分进行隔离,从而使得业务逻辑各个部分的耦合度降低,提高程序的可用性,同时提高开发效率。
1. 静态代理
Student:
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student() {
}
public void study(String name) {
System.out.println(name + "在学习");
}
}
$Student:
public class $Student {
private Student stu;
public Student getStu() {
return stu;
}
public void setStu(Student stu) {
this.stu = stu;
}
public $Student(Student stu) {
this.stu = stu;
}
public void study() {
System.out.println(stu.getName() +"准备学习");
stu.study(stu.getName());
System.out.println(stu.getName() +"学完了");
}
}
Test:
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.setName("Tom");
$Student stu2 = new $Student(stu1);
stu2.study();
}
}
2. 动态代理
1) 先建一个IStudent接口,让Student类实现这个接口
publicinterface IStudent {
public void study();
}
2) 建Student类
3) 建动态代理类DynamicProxy
publicclass DynamicProxy implements InvocationHandler {
private Object obj;
public static Object newInstance(Object obj){
returnProxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(),new DynamicProxy(obj));
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public DynamicProxy(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Methodmethod, Object[] args)
throws Throwable {
Object result = null;
try {
System.out.println(method.getName()+ "执行前");
result = method.invoke(obj,args);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(method.getName()+ "执行后");
}
return result;
}
public static void main(String[] args) {
IStudent istu = newStudent("Tom");
IStudent istu1 = (IStudent)DynamicProxy.newInstance(istu);
istu1.study();
}
}
十六. AOP术语:
1. 方面/切面:分装共同处理的组件,该组件被作用到其它的目标组件上
2. 目标:是指被一个或多个方面所作用的对象。
3. 切入点/连接点:切入点是为了指定哪些组件和方法使用方面功能,在Spring中使用表达式指定切入目标
4. 通知:用于指定方面组件和目标组件的作用时机,例如方面组件功能在目标方法之前或之后执行等时机
Spring中的通知:
a) 前置通知
b) 后置通知
c) 最终通知
d) 异常通知
e) 环绕通知
try{
//前置通知
//环绕通知——前置部分
//目标组件方法
//环绕通知——后置部分
}catch(){
//异常通知
}finally{
//最终通知
}
十七. Spring AOP实现原理
主要是基于动态代理技术,Spring Aop主要实现动态代理技术,当Spring采用AOP配置后,Spring容器返回给目标对象,实际上是Spring采用动态代理技术生成的一个代理类,代理类生成了原目标组件方法和功能,在代理类中调用方法对象功能和目标对象功能。
Spring框架的两种动态代理实现:
1) cglib工具包——目标没有接口时采用此方法
2) JDK Proxy API——目标具有接口时采用此方法
关于动态代理的机制
1. 通过获取代理目标的接口,使用proxyTarget方法产生一个代理类,该代理类实现了代理目标的所有接口
2. 交给代理类代理执行方法都应该写在接口中,这样接口也应该由代理目标来实现。
3. 通过Spring获取代理工厂,并生成动态代理类后,所要执行的方法是通过反射的invoke方法来执行
4. Invoke执行,此时调用的是代理工厂的invoke方法,由代理工厂的invoke方法再去回调动态代理类的invoke方法,动态代理类再去回调代理目标的真正的invoke方法
Factory(invoke)——动态代理类(invoke)——真正的invoke方法(invoke)
十八. Aop的开发步骤
1. 创建方面组件:创建一个类充当方面组件,实现通用业务逻辑;
2. 声明方面组件,在applicationContext.xml中,声明方面组件
3. 使用方面组件,在applicationContext.xml中,将方面组件作用到目标组件上,并设置通知类型确认方面组件的调用时机。
例子:定义一个IStudent接口和一个Student类,
定义通知
后置通知:
publicclass AfterAdvice implements AfterReturningAdvice {
public void afterReturning(Object resule,Method method, Object[] args,
Object o) throws Throwable {
// result:返回结果
// method:调用方法
// args:执行方法调用的参数
// o:调用该目标方法的对象
System.out.println("后置通知。。。。。");
}
}
前置通知:
public class BeforeAdvice implementsMethodBeforeAdvice {
public void before(Method method, Object[]args, Object obj)
throws Throwable {
// method:目标组件中调用的方法
// args:目标组件调用时传入的参数
// obj:调用method方法的对象
System.out.println("前置通知。。。。。");
}
}
环绕通知:
publicclass AroundAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation invoke)throws Throwable {
System.out.println("环绕通知的前部分。。。。");
Object o = invoke.proceed();
System.out.println("环绕通知的后部分。。。。");
return o;
}
}
在xml中配置:
<!-- 要被代理的目标-->
<bean id="student"class="com.xff.proxy.Student" >
<propertyname="name" value="Tom"></property>
</bean>
<!-- 配置代理类 -->
<bean id="proxy"class="org.springframework.aop.framework.ProxyFactoryBean">
<!--配置要代理的目标 -->
<propertyname="target">
<refbean="student"/>
</property>
<!--指定通知 -->
<propertyname="interceptorNames">
<list>
<value>befordAdvisor</value>
<value>afterAdvisor</value>
<value>arountAdvisor</value>
</list>
</property>
</bean>
<!-- 配置切入点 -->
<bean id="pointCut"class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<!--满足表达式的方法 -->
<propertyname="pattern" value=".*study"></property>
</bean>
<!-- 通知 -->
<!-- 前置通知 -->
<bean id="beforeAdvice"class="com.xff.aspect.BeforeAdvice"/>
<bean id="befordAdvisor"class="org.springframework.aop.support.DefaultPointcutAdvisor">
<propertyname="advice" ref="beforeAdvice"/>
<propertyname="pointcut" ref="pointCut"/>
</bean>
<!-- 后置通知 -->
<bean id="afterAdvice"class="com.xff.aspect.AfterAdvice"/>
<bean id="afterAdvisor"class="org.springframework.aop.support.DefaultPointcutAdvisor">
<propertyname="advice" ref="afterAdvice"/>
<propertyname="pointcut" ref="pointCut"/>
</bean>
<!-- 环绕通知 -->
<bean id="arountAdvice"class="com.xff.aspect.AroundAdvice"/>
<bean id="arountAdvisor"class="org.springframework.aop.support.DefaultPointcutAdvisor">
<propertyname="advice" ref="arountAdvice"/>
<propertyname="pointcut" ref="pointCut"/>
</bean>
测试类:
publicstatic void main(String[] args) {
ApplicationContextac = new ClassPathXmlApplicationContext(
"applicationContext.xml");
IStudentstu = ac.getBean("proxy", IStudent.class);
stu.study();
}
十九. Sring总结
Spring框架核心是IOC和AOP,IOC是依赖注入,把对象的创建和管理交个Spring容器,可以降低项目之间的耦合度,维护对象之间的依赖关系,即DI。
其实这些关系是用反射机制来实现的。反射可以获取到类的信息,得到类的信息后可以通过类的一些配置信息去动态调用里面的方法或访问里面的属性,使得框架更加灵活。
二十.