Spring 原理 架构 详解 总结! (看HSP笔记)

来源:互联网 发布:还珠格格燕子复仇知画 编辑:程序博客网 时间:2024/05/21 10:40

u  spring的快速入门案例

 

①    spring是什么?

struts 是 web 框架(jsp/action/actionfrom)

hibernate 是 orm框架,处于持久层.

spring 是容器框架,用于配置bean,并维护bean之间关系的框架

☞ spring中有一个非常概念: bean (是java中的任何一种对象javabean/service/action/数据源./dao, ioc(控制反转 inverse of control) di( dependency injection 依赖注入)

☞ 画一个框架图

u  快速入门

 

开发一个spring项目.

 

1.      引入spring的开发包(最小配置spring.jar 该包把常用的jar都包括, 还要写日志包 common-logging.jar

2.      创建spring的一个核心文件applicationContext.xml, [hibernate有核心 hibernate.cfg.xml struts核心文件 struts-config.xml], 该文件一般放在src目录下,该文件中引入 xsd文件 :

可以从给出的案例中拷贝一份.

3.      配置bean

<!-- 在容器文件中配置bean(service/dao/domain/action/数据源) -->

<!-- bean元素的作用是,当我们的spring框架加载时候,spring就会自动的创建一个bean对象,并放入内存

UserService userSerivce=new UserService();

userSerivce.setName("韩顺平");

-->

<beanid="userService" class="com.service.UserService">

<!-- 这里就体现出注入的概念. -->

<property name="name">

        <value>韩顺平</value>

</property>

</bean>

4.      在Test.java中,我们怎么使用

//我们现在使用spring来完成上面的任务

              //1.得到spring 的applicationContext对象(容器对象)

              ApplicationContextac=new ClassPathXmlApplicationContext("applicationContext.xml");

              UserServiceus=(UserService) ac.getBean("userService");

              us.sayHello();

5.      细节讨论?

传统的方法和使用spring的方法

           使用spring ,没有new 对象,我们把创建对象的任务交给spring框架

           spring的运行原理图:

 

5.3我们再看spring

 

对上面案例总结:

spring实际上是一个容器框架,可以配置各种bean(action/service/domain/dao),并且可以维护bean与bean的关系,当我们需要使用某个bean的时候,我们可以getBean(id),使用即可.

 

ioc是什么?

答 :ioc(inverse of controll ) 控制反转: 所谓控制反转就是把创建对象(bean),和维护对象(bean)的关系的权利从程序中转移到spring的容器(applicationContext.xml),而程序本身不再维护.

 

DI是什么?

答:di(dependency injection) 依赖注入: 实际上di和ioc是同一个概念,spring设计者认为di更准确表示spring核心技术

 

☞ 学习框架,最重要的就是学习各个配置.

 

把Applicationcontext做成一个单例的.

 

上机练习: 把我写的代码走一遍.

 

 

u  spring开发提倡接口编程,配合di技术可以层与层的解耦

举例说明:

现在我们体验一下spring的di配合接口编程的,完成一个字母大小写转换的案例:

思路:

1.      创建一个接口 ChangeLetter

2.      两个类实现接口

3.      把对象配置到spring容器中

4.      使用

 

通过上面的案例,我们可以初步体会到di配合接口编程,的确可以减少层(web层) 和业务层的耦合度.

 

思考题:

 

接口

ValidateUser

有一个方法:

check(??)

有两个类

CheckUser1 implements ValidateUser

{

       check//安装xml验证

}

CheckUser2implements VallidateUser{

check()// 到数据库去验证

}

 

 

从ApplicationContex 应用上下文容器中获取bean和从bean工厂容器中获取bean

 

具体案例:

//从ApplicationContext中取bean

ApplicationContextac=new ClassPathXmlApplicationContext("com/hsp/ioc/beans.xml");

//当我们去实例化beans.xml,该文件中配置的bean被实例(该bean scope是 singleton)从bean中取出student

             

             

              //如果我们使用beanfactory去获取bean,当你只是实例化该容器, 那么

              //容器的bean不被实例化,只有当你去使用getBean某个bean时,才会实时的创建.

             

              BeanFactory factory = newXmlBeanFactory(

                            newClassPathResource("com/hsp/ioc/beans.xml"));

              factory.getBean("student");

结论:

1.如果使用ApplicationContext ,则配置的bean如果是 singlton不管你用不用,都被实例化.(好处就是可以预先加载,缺点就是耗内存)

2.如果是 BeanFactory ,则当你获取beanfacotry时候,配置的bean不会被马上实例化,当你使用的时候,才被实例(好处节约内存,缺点就是速度)

3.规定: 一般没有特殊要求,应当使用ApplicatioContext完成(90%)

 

u  bean 的  scope的细节

入门案例:

//获取两个student

              Students1=(Student) ac.getBean("student");

              Students2=(Student) ac.getBean("student");

              System.out.println(s1+""+s2);

 

l  request

l  session

l  global-session

是在web开发中才有意义.

三种获取ApplicationContext 对象引用的方法

 

1.      ClassPathXmlApplicationContext-> 通过类路径

2.      FileSystemXmlApplicationContext-> 通过文件路径

举例:

ApplicationContext ac=newFileSystemXmlApplicationContext("文件路径beans.xml / applicationContext.xml");

3.      XmlWebApplicationContext

 

u    bean的生命周期

为什么总是一个生命周期当做一个重点?

Servlet -> servlet生命周期 init() destory()

java对象生命周期.

往往笔试,面试总喜欢问生命周期的问题

 

 

①    实例化(当我们的程序加载beans.xml文件),把我们的bean(前提是scope=singleton)实例化到内存

②    调用set方法设置属性

③    如果你实现了bean名字关注接口(BeanNameAware)则,可以通过setBeanName获取id号

④    如果你实现了 bean工厂关注接口,(BeanFactoryAware),则可以获取BeanFactory

⑤    如果你实现了 ApplicationContextAware接口,则调用方法

//该方法传递ApplicationContext

       publicvoid setApplicationContext(ApplicationContext arg0)

                     throwsBeansException {

              //TODO Auto-generated method stub

              System.out.println("setApplicationContext"+arg0);

             

       }

⑥    如果bean 和 一个后置处理器关联,则会自动去调用 Object postProcessBeforeInitialization方法

⑦    如果你实现InitializingBean 接口,则会调用 afterPropertiesSet

⑧    如果自己在<bean init-method=”init” /> 则可以在bean定义自己的初始化方法.

⑨    如果bean 和 一个后置处理器关联,则会自动去调用 Object postProcessAfterInitialization方法

⑩    使用我们的bean

 

11. 容器关闭

12. 可以通过实现DisposableBean 接口来调用方法 destory

13. 可以在<bean destory-method=”fun1”/> 调用定制的销毁方法

 

小结: 我们实际开发中往往,没有用的这么的过程,常见的是:

1->2->6->10->9->11

 

上机练习: 把使用每个 bean的时间记录到一个recoder.txt文件 ,内容是

xxbean. 使用时间是 :  1999-11-11 11:11:11

 

 

问题:通过BeanFactory来获取bean对象,bean的生命周期是否和Applicationcontext 是一样吗?

不是一样的,bean是工厂中创建的生命周期会简单一些:

 

u  配置bean的细节

 

① scope 的说明:

 

☞ 尽量使用 scope=”singleton”,不要使用prototype,因为这样对我们的性能影响较大.

 

 

 

②    如何给集合类型注入值.

java中主要的集合有几种: map set list / 数组

 

Department类:

package com.hsp.collection;

 

import java.util.List;

import java.util.Map;

import java.util.Set;

 

public class Department {

 

       privateString name;

       privateString [] empName;

       privateList<Employee> empList;

       privateSet<Employee> empsets;

       privateMap<String,Employee> empMaps;

      

       publicSet<Employee> getEmpsets() {

              returnempsets;

       }

       publicvoid setEmpsets(Set<Employee> empsets) {

              this.empsets= empsets;

       }

       publicString[] getEmpName() {

              returnempName;

       }

       publicvoid setEmpName(String[] empName) {

              this.empName= empName;

       }

       publicString getName() {

              returnname;

       }

       publicvoid setName(String name) {

              this.name= name;

       }

       publicList<Employee> getEmpList() {

              returnempList;

       }

       publicvoid setEmpList(List<Employee> empList) {

              this.empList= empList;

       }

       publicMap<String, Employee> getEmpMaps() {

              returnempMaps;

       }

       publicvoid setEmpMaps(Map<String, Employee> empMaps) {

              this.empMaps= empMaps;

       }

 

}

 

//Employeel类

package com.hsp.collection;

public class Employee {

       privateString name;

       privateint id;

       publicint getId() {

              returnid;

       }

       publicvoid setId(int id) {

              this.id= id;

       }

       publicString getName() {

              returnname;

       }

       publicvoid setName(String name) {

              this.name= name;

       }

}

 

beans.xml配置文件:

<?xml version="1.0"encoding="utf-8"?>

<beansxmlns="http://www.springframework.org/schema/beans"

              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

              xmlns:context="http://www.springframework.org/schema/context"

              xmlns:tx="http://www.springframework.org/schema/tx"

              xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd

                            http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd

                            http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

 

<bean id="department"class="com.hsp.collection.Department">

<property name="name"value="财务部"/>

<!-- 给数组注入值-->

<propertyname="empName">

       <list>

              <value>小明</value>

              <value>小明小明</value>

              <value>小明小明小明小明</value>

       </list>

</property>

<!-- list注入值 list中可以有相当的对象 -->

<propertyname="empList">

       <list>

              <ref bean="emp2" />

              <ref bean="emp1"/>

              <ref bean="emp1"/>

              <ref bean="emp1"/>

              <ref bean="emp1"/>

              <ref bean="emp1"/>

              <ref bean="emp1"/>

       </list>

</property>

<!-- set注入值set不能有相同的对象 -->

<propertyname="empsets">

       <set>

              <ref bean="emp1" />

              <ref bean="emp2"/>

              <ref bean="emp2"/>

              <ref bean="emp2"/>

              <ref bean="emp2"/>

       </set>

</property>

<!-- map注入值 map只有key不一样,就可以装配value -->

<propertyname="empMaps">

       <map>

              <entry key="11" value-ref="emp1"/>

              <entry key="22"value-ref="emp2"/>

              <entry key="33"value-ref="emp1"/>

       </map>

</property>

<!-- 给属性集合配置-->http协议 referer

<propertyname="pp">

       <props>

              <prop key="pp1">abcd</prop>

              <prop key="pp2">hello</prop>

       </props>

</property>

</bean>

<bean id="emp1"class="com.hsp.collection.Employee">

<property name="name"value="北京"/>

<property name="id"value="1"/>

</bean>

<bean id="emp2"class="com.hsp.collection.Employee">

<property name="name"value="天津"/>

<property name="id"value="2"/>

</bean>

</beans>

③    内部bean

<bean id=”foo” class=”....Foo”>

       <propertyname=”属性”>

       <!—第一方法引用-->

       <refbean=’bean对象名’/>

       <!—内部bean-->

       <bean>

       <properyt></property>

</bean>

</property>

</bean>

④    继承配置

 

public class Student

public class Gradate extends Student

 

在beans.xml文件中体现配置

<!-- 配置一个学生对象 -->

<bean id="student"class="com.hsp.inherit.Student">

       <propertyname="name" value="顺平" />

       <propertyname="age" value="30"/>

</bean>

<!-- 配置Grdate对象 -->

<bean id="grdate"parent="student" class="com.hsp.inherit.Gradate">

       <!-- 如果自己配置属性name,age,则会替换从父对象继承的数据  -->

       <propertyname="name" value="小明"/>

       <propertyname="degree" value="学士"/>

</bean>

 

 

思考: 目前我们都是通过set方式给bean注入值,spring还提供其它的方式注入值,比如通过构造函数注入值!

 

通过构造函数注入值

 

beans.xml 关键代码:

<!-- 配置一个雇员对象 -->

<bean id="employee"class="com.hsp.constructor.Employee">

<!-- 通过构造函数来注入属性值 -->      

<constructor-arg index="0"type="java.lang.String" value="大明" />

</bean>

 

u  自动装配bean的属性值

 

 

(1)   byName的用法:

<!-- 配置一个master对象 -->

<bean id="master"class="com.hsp.autowire.Master" autowire="byName">

<property name="name">

<value>顺平</value>

</property>

</bean>

<!-- 配置dog对象 -->

<bean id="dog" class="com.hsp.autowire.Dog">

<property name="name"value="小黄"/>

<property name="age"value="3"/>

</bean>

原理图:

 

(2)   byType: byType:寻找和属性类型相同的bean,找不到,装不上,找到多个抛异常。

(3)   constructor: autowire="constructor"

说明 :查找和bean的构造参数一致的一个或

     多个bean,若找不到或找到多个,抛异常。按照参数的类型装配 

 

(4) autodetect

 

说明 :  autowire="autodetect"

(3)和(2)之间选一个方式。不确定

      性的处理与(3)和(2)一致。

(5) defualt

这个需要在<beansdefualt-autorwire=“指定” />

当你在<beans>指定了default-atuowrite后, 所有的bean的 默认的autowire就是 指定的装配方法;

如果没有在<beansdefualt-autorwire=“指定” /> 没有  defualt-autorwire=“指定” ,则默认是

defualt-autorwire=”no”

(6) no: 不自动装配

 

 

使用spring的特殊bean,完成分散配置:

 

beans.xml

说明: 当通过 context:property-placeholder 引入 属性文件的时候,有多个需要使用 , 号间隔.

<!-- 引入我们的db.properties文件 -->

<context:property-placeholderlocation="classpath:com/hsp/dispatch/db.properties,classpath:com/hsp/dispatch/db2.properties"/>

<!-- 配置一DBUtil对象 $占位符号 -->

<bean id="dbutil"class="com.hsp.dispatch.DBUtil">

<property name="name"value="${name}" />

<property name="drivername"value="${drivername}" />

<property name="url"value="${url}" />

<property name="pwd"value="${pwd}" />

</bean>

 

<!-- 配置一DBUtil对象 -->

<bean id="dbutil2"class="com.hsp.dispatch.DBUtil">

<property name="name"value="${db2.name}" />

<property name="drivername"value="${db2.drivername}" />

<property name="url" value="${db2.url}"/>

<property name="pwd"value="${db2.pwd}" />

</bean>

 

db.properties:

name=scott

drivername=oracle:jdbc:driver:OracleDirver

url=jdbc:oracle:thin:@127.0.0.1:1521:hsp

pwd=tiger

 

 

u  aop编程

aop( aspect oriented programming ) 面向切面(方面)编程,是对所有对象或者是一类对象编程,核心是( 在增加代码的基础上,增加新功能 )

 

汇编(伪机器指令 mov jump) 面向机器

c语言(面向过程  )->系统软件(操作系统,数据库, 杀毒软件,防火墙,驱动..)

 

语句1;

语句2;

...

 

 

 

java语法(面向对象->类-对象)

 

class Dog{

       属性;->变量

       行为->函数

}

 

面向切面 spring( ->aop) 面向n多对象编程

 

aop特别提醒: aop编程,实际上在开发框架本身用的多,在实际项目中,用的不是很多,但是将来会越来越多,这个一个趋势.

 

u aop原理+案例

 

 

编程说明:

步骤:

1.       定义接口

2.       编写对象(被代理对象=目标对象)

3.      编写通知(前置通知目标方法调用前调用)

4.      在beans.xml文件配置

           配置 被代理对象=目标对象

           配置通知

           配置代理对象 是 ProxyFactoryBean的对象实例

           <!--代理接口集 -->

           织入通知

           配置被代理对象

 

后面还后置通知,环绕通知,异常通知,引入通知

上机: 你把老师写的代码看看,走一遍。

 

 

 

 

提问? 说spring的aop中,当你通过代理对象去实现aop的时候,获取的ProxyFactoryBean是什么类型?

答: 返回的是一个代理对象,如果目标对象实现了接口,则spring使用jdk 动态代理技术,如果目标对象没有实现接口,则spring使用CGLIB技术.

 

 

 

 

 

 

 

提一个问题

 

class A{

       private Strinag name;

       public viodsetName(String name){

   this.name=name;

System.out.println(“name”+name);

}

}

beans.xml

<bean id=”a” class=”...A”>

<property name=”name” value=”顺平” />

</bean>

A a=new A();

a.setName(“顺平”);

 


原创粉丝点击