从三层架构到Spring框架

首先是软件的应用分层架构
  标准三层架构:
    1:数据访问层:实现了数据的持久化
    2:业务逻辑层:对逻辑的实现及处理,实际上不可能在表示层对数据不做任何处理,但是尽可能的将逻辑分为一层
    3:表示层:数据的展示

  优点:
    降低了一个程序的耦合度,一个类中有一千行代码可以转化为三个类中各写300多行代码,每个类实现自己的功能
  慢慢的就形成了一种标准化趋势,更加的适应于面向接口编程,注重《开闭原则》的实现,对修改关闭,而对扩展开放,
  扩展的功能定义为接口,程序员进行实现,在现有的代码中组合进新功能的实现类对象,从而实现新功能的添加。

  缺点:
    然而这种三层体系架构依旧存在一些问题
    1.有些时候将简单的问题复杂化,假如:
      一个类300代码可以完成的工作,分为三层架构后每个类需要120行代码进行完成,反而得不偿失了
    2.组合的代码不一定有效,例如:
      有这样一个类:

     public class A{
        private IB b=new BImpl();
        public void go(){
        b.go();
        }    
        public static void main(String agrs[]){
          new A().go();
        }
      }

这个例子可以看出,一旦IB接口的实现类BImpl出现了问题,那么b.go()可能空指针异常,A类中的方法就无法正常运行

那么:有没有一种方法可以不使用组合的方式来获得对象?
  Java中创建对象对象除了new关键字之外,有的就是反射机制了。有效的破坏莫不失为一种好想法,有了反射我们就可以直接通过权限定名来创建对象。

Spring框架的相关概念
轻量级:spring是一种轻量级框架,用户可以自定义自己需要的内容,选择自己需要的功能模块

容器的概念:
Java开发中常见的容器有:GUI,Tomcat都是一些容器,比如jsp动态页面的展示,就是需要Tomcat容器的支持才可以运行。spring框架中的容器可以管理项目中各种对象的生命周期(对象的创建、初始化、使用、销毁)
前提是项目中要使用spring框架,并且把这些需要管理的对象配置给spring的容器,常见的IOC容器可以控制bean对象的

但是这个bean对象一般都是单例的。
生成生命周期,当然前提是对象不可以脱离容器控制范围(单例对象和多例对象)

spring框架给项目带来的好处:
1)动态解藕,方便开发,面向接口设计
我们可以将对象之间的依赖关系交由Spring进行控制
2)方便程序的测试
spring框架也提供了测试模块,可以和很多主流的测试框架相结合
3)降低Java EE API的使用难度
Spring封装了如jdbc等许多有难度的操作,使得代码“相对”精简。
这里的相对是说,使用了框架相当于在项目中已经引入了代码,所以说Java之所以有许多人用,那是因为Java的类库太丰富了
Spring功能足够强大,但是又可以自己选择模块,这就十分人性化了。
但是Java在程序的效率方面来说是比不上C和C++了。
4)方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度
Spring提供了对各种优秀框架(如Struts,Hibernate,MyBatis)等的直接支持
5)AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程
6)声明式事务的支持
在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量
7)spring是一个模块化的项目,可以根据自己的需要定制功能模块

spring的核心宗旨:简化企业级应用开发,同时给复杂问题提供强大的、非侵入性解决方案

Spring核心功能模块 Spring Framework
在Spring Framework中又分为许多的模块
Spring Context(spring的上下文)
Spring Web
Spring DAO
Spring ORM
Spring AOP(面向切面编程)
Spring MVC(Spring WebMVC)

Spring Core(spring的核心容器)
这个容器是Spring的一个核心容器

我当前主要学习了的是spring Core和spring AOP,也就是spring框架所提供的ioc和aop功能
Spring MVC是一个集成化的web开发框架,不恰当的说它的地位甚至可以将其从Spring中分离出来,作为一个单独的框架

spring中的IOC
IOC:Inversion of Control 控制反转
spring核心容器也可以称为IOC容器,该容器主要负责管理各种对象的生命周期(对象的创建、初始化、销毁等)
IOC容器并没有实现更多的功能,但它的存在使我们不需要很多代码、不需要考虑对象间复杂的耦合关系就能从IOC容器中获取合适的对象
而且提供了各种对象的可靠的管理,极大地降低了开发的复杂性。

思考1:是什么东西的"控制"被"反转"了?
简单的说:是对象被控制了起来,创建对象的操作反转给了框架
思考2:自己组装电脑和直接购买整机的区别

DI:Dependency Injection 依赖注入
DI的概念的提出是用来代替IOC的,表示让调用类对某一接口实现类的依赖关系由容器注入,以移除调用类对某一接口实现类的依赖。(思考servlet和service层接口以及service层接口实现类这三者的关系)
依赖注入 这个名词显然比 控制反转 更直接明了,并且易于理解。

DL:Dependency Loopup 依赖查找
容器创建对象并提供 回调接口和上下文环境 给这个对象,需要时通过接口从容器中查找其他对象
(之后会见到很多XxxxAware的接口,先简单理解即可)

Spring IOC容器核心api(容器将来会是一个对象)
BeanFactory接口
BeanFactory是Spring中IOC容器的核心接口,主要用于处理Bean的初始化和配置,建立对象间的依赖关系

接口中主要方法如下:
//根据指定名称返回一个Bean实例
Object getBean(String name)

//判断名称为name的Bean是否是原型,即是否总是返回一个新实例(非单例)
boolean isPrototype(String name)

//判断名称为name的Bean是否是单例
boolean isSingleton(String name)

//判断容器中是否包含给定名称的Bean实例
boolean containsBean(String name)

//如果名称为name的Bean有别名则返回所有别名
String[] getAliases(String name)

ApplicationContext接口
该接口继承于BeanFactory,增强了BeanFactory,增加了事务处理AOP,国际化,事件传递等功能

所以在代码中我们一般会使用ApplicationContext接口,以及这个接口相应的实现类来创建spring的容器对象
例如:
String path = "com/briup/ioc/set/set.xml";
ApplicationContext container =
new ClassPathXmlApplicationContext(path);

Student s = (Student)container.getBean("student");
//使用s即可

三层关系如下:

BeanFactory

ApplicationContext

ClassPathXmlApplicationContext

配置文件
这是一个框架中必不可少的部分,会写Spring的XML文件一定会用Spring框架,但是会用不一定明白为什么这么用......
Spring通过读取配置文件中的数据来对项目各个对象进行实例化,配置以及组装,通常使用XML文件来作为配置文件

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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
......
</beans>

IOC的相关功能

IOC实际上就是实现的Spring容器帮助我们管理对象的功能,所以要先从如何将对象注入到容器中来学习

注入有两种方式:set注入和构造器注入,自动注入和继承也属于这个知识点内

set方式注入(必须依靠set方法)

顾名思义,实现set方式的注入就必须存在set方法
这种动态代理的方式创建对象是反射机制,如果是set注入就必须要无参构造器的支持

可以注入的内容有:
  1基本类型(8中基本类型+字符串)的装配
  2对象类型的装配
  3集合的装配

1.基本类型的装配
方式: 配置元素<value/>
例子:

public class HelloBean {
private String name;
private int age;
public String sayHello(){
return "hello "+name +",your age is" + age;
}
.............
}


配置文件set.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<bean id="helloBean" class="ioc.HelloBean">
<property name="name">
<value>tom</value>
</property>
<property name="age" value="20">
</property>
</bean>
</beans>

id是Bean的唯一标识,要求在整个配置文件中要唯一
也可使用name属性,bean标签里面的id和name属性都可以用来标识这个配置的对象
但是id会帮我们检查给对象起的名字是否规范(名字不能重复、不能用数字开头、不能有空格等等)
如果检查出来了那么就会报错name属性不会帮检查这些东西

property 对于所有用set方式来注入的必须使用该标签
value 是对于基本类型,都用value(标签/属性)来注入,可以实现自动的数据类型转换
这里的自动数据类型不是绝对的,自定义的类型不可以自动的数据类型转换
如果有这方面的要求,就需要实现一个类型处理器。

测试类:

main:
ApplicationContext ac = 
new ClassPathXmlApplicationContext("set.xml");
//获取容器的一个实例
HelloBean hb = (HelloBean) ac.getBean("helloBean");
System.out.println(hb.sayHello());


2.对象类型的装配
1.<ref local=" "/> 用于涉及的对象的id在本配置文件中
2.<ref bean=" "/> 用于涉及的对象的id不在本配置文件中
3.使用property的ref属性引用,这样就不需要处理涉及到的对象在不在同一个xml配置文件中

例如:

public class OtherBean {
private String str1;
public String getStr1() {
return str1;
}
public void setStr1(String str1) {
this.str1 = str1;
}
public String toString(){
return "OtherBean "+str1;
}
}
public class SomeBean {
private OtherBean ob;
public void printInfo(){
System.out.println("someBean "+ob);
}
public OtherBean getOb() {
return ob;
}
public void setOb(OtherBean ob) {
this.ob = ob;
}
}

配置applicationContext.xml

<bean id="someBean" class="ioc.SomeBean">
<property name="ob">
<!-- <ref bean=" "/> 用于涉及的对象的id不在本配置文件中 -->
<ref bean="otherBean" />
</property>
</bean>

配置other.xml文件

<bean id="otherBean" class="ioc.OtherBean">
<property name="str1">
<value>hello</value>
</property>
</bean>

测试类:

main:
String[] path = {"ioc/applicationContext.xml","ioc/other.xml"};
ApplicationContext ac = new ClassPathXmlApplicationContext(path);
SomeBean sb = (SomeBean) ac.getBean("someBean");
sb.printInfo(); 

3.集合的装配
方式:配置元素<list> <set> <map> <props>
例如:

public class SomeBean {

private List listProperty;
private Set setProperty;
private Map mapProperty;
private Properties<String,String> property;

get/set......

toString();
}

applicationContext.xml的写法:

<bean id="someBean" class="ioc.SomeBean">
<property name="listProperty">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<property name="setProperty">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<property name="mapProperty">
<map>
<entry key="key1">
<value>value1</value>
</entry>
<entry key="key2">
<value>value2</value>
</entry>
</map>
</property>

<property name="property">
<props>
<prop key="key1">prop1</prop>
<prop key="key2">prop2</prop>
<prop key="key3">prop3</prop>
</props>
</property>
</bean>

测试类:

main:
String path = "ioc/applicationContext.xml";
ApplicationContext ac =
new ClassPathXmlApplicationContext(path);
SomeBean sb = (SomeBean) ac.getBean("someBean");
sb.printInfo();

基于构造器注入
方式: 配置<constructor-arg>元素
在Bean中不用写set方法,但是要有相应的构造器

构造器注入有俩种形式 一个是根据参数类型 一个是根据参数位置的下标
<constructor-arg type="int" value="">
<constructor-arg index="0" value="">

例如:

<bean name="student" class="com.briup.bean.Student">
<constructor-arg type="int" value="25">
</constructor-arg>

<constructor-arg type="java.lang.String" value="tom">
</constructor-arg>

<constructor-arg type="long" value="100">
</constructor-arg>

</bean>

或者:

<bean name="student" class="com.briup.bean.Student">
<constructor-arg index="2">
<value>30</value>
</constructor-arg>

<constructor-arg index="0">
<value>200</value>
</constructor-arg>

<constructor-arg index="1">
<value>lily</value>
</constructor-arg>
</bean>

构造器注入有俩种形式 一个是根据参数类型 一个是根据参数位置的下标 
还有指定参数传参 这里的name指的是形参的参数名字 

<bean name="student" class="com.briup.bean.Student">
<constructor-arg index="0" value="2" name="a"></constructor-arg>
<constructor-arg index="1" value="3" name="b"></constructor-arg>
<constructor-arg index="2" value="4" name="c"></constructor-arg>
</bean>

自动注入 :容器依照一些规则去装配bean中的一个属性
注意:自动装配只对[对象类型]起作用,对基本类型不起作用.
第一种情况:
在beans标签中配置装载方式:default-autowire="byName"

在根元素beans中加入这个属性,那么下面所有的bean都会
使用byName的方式进行自动注入,如果在下面的某一个bean
里面想使用其他的方式进行注入,可以用autowire=""属性进行
说明,或者某一个bean不想使用任何自动注入就使用autowire="no"

第二种情况:
在bean标签中指定配置方式

autowire="byName":
spring容器会到当前的类中找property的名字,然后
再根据这个名字去spring容器中找有没有和这个property
名字相同的对象,有的话,就把这个对象当做参数放到
setXxxx这个方法里面注入进来.

比如Teacher类中有一个属性Student student
对应的有setStudent()方法
在xml中配置了Student这个类。
name="studnet";
Spring在自动注入Teacher类中的student属性的时候就会去找和这个property
名字相同的对象

<bean name="t" class="com.briup.bean.Teacher" autowire="byName">
<property name="id" value="10"></property>
<property name="name" value="王老师"></property>
<!-- <property name="student" ref="stu"></property> -->
</bean>

注意:了解property指的类中的什么东西
property来源于attribute
property name="xxxx"实际上就是setXxxx()
这四个xxxx是一个含义

autowire="byType":
spring容器会根据当前类中的set方法里面参数的类型,
去容器中找相匹配的对象,如果没找到就算了,如果找到
一个就注入进来,如果找到多个,那么就会报错了.

也就是说找不到大不了就赋值为null,但是找到两个框架报错了,因为框架不知道用哪个啊
所以说要么就不写,写了就不要有歧义。

autowire="constructor"
根据构造器的参数类型去匹配


继承
配置文件中,一个bean的配置可以继承另一个bean的配置

bean标签中的俩个属性:
abstract属性
<bean name=".." class=".." abstract="true">
注:bean中一旦定义为了abstract="true",则说明该bean是用来被继承的,不能通过该bean获得对象了

parent属性,指定继承哪个bean的配置
<bean name=".." parent="另一个bean的名字">

例子:

<bean name="student" class="com.briup.bean.Student">
<property name="name">
<value>zhangsan</value>
</property>
</bean>

abstract="true" 表示当前的配置是一个抽象的配置,
这时候我们在代码中就不能通过这个bean的名字teacher来
获得相应的对象了(和java中的抽象类不能直接new对象的道理一样)

但是我们可以再写一个配置去继承这个抽象的配置,当然即使当前
这个配置不是抽象的,也能够被继承(和java中继承一样)

<bean name="teacher" class="com.briup.bean.Teacher" abstract="true">
<property name="student" ref="student"></property>
</bean>

parent="teacher" 表示当前配置是继承了另外一个名字叫
teacher的bean的配置,配置和配置的继承像java中的类和类
直接的继承一样,子类会把父类中的对象继承过来.
当然在子配置里面依然是可以覆盖父配置中已经写的配置信息.

<bean name="t" parent="teacher">    
<property name="id">
<value>11</value>
</property>
<property name="name">
<value>TeacherWang</value>
</property>
</bean>
原文地址:https://www.cnblogs.com/Magic-Li/p/11722976.html