spring初学 摘记

 spring简介

        Spring的核心是个轻量级容器(container),实现了IoC(Inversion of Control)模式的容器,Spring的目标是实现一个全方位的整合框架,在Spring框架下实现多个子框架的组合,这些子框架之间彼此可以独立,也可以使用其它的框架方案加以替代,Spring希望提供one-stop shop的框架整合方案 

Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。

 

轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。

此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。

控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

容器—Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

 框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。 


spring框架组成

Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,如下图所示:


Spring 框架的分为7个模块,组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下: 

1.核心容器:核心容器提供 Spring 框架的基本功能,核心模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。

2.Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。

3.Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。

 4. Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。

 5.Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。

6. Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

7. Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。


总结起来,Spring有如下优点:

1.低侵入式设计,代码污染极低

2. 独立于各种应用服务器,可以真正实现Write Once,Run Anywhere的承诺

3.Spring的DI机制降低了业务对象替换的复杂性

4.Spring并不完全依赖于Spring,开发者可自由选用Spring框架的部分或全部     

 

 IOC 和 AOP:这两个概念可以算是spring中的核心 

控制反转模式也称作依赖性介入)的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器 (在 Spring 框架中是 IOC 容器) 负责将这些联系在一起。在典型的 IOC 场景中,容器创建了所有对象,并设置必要的属性将它们连接在一起,决定什么时间调用方法。

 

控制反转:当某个java 对象需要(依赖)另一个java 对象时,不是自身直接创建依赖对象,而是由实现IoC 的容器(如spring 框架的IoC容器)来创建,并将它注入需要这个依赖对象的java 对象中。

类型 1

服务需要实现专门的接口,通过接口,由对象提供这些服务,可以从对象查询依赖性(例如,需要的附加服务),这种用的很少

类型 2

通过 JavaBean 的属性(例如 setter 方法)分配依赖性

类型 3

依赖性以构造函数的形式提供,不以 JavaBean 属性的形式公开

Spring 框架的 IOC 容器主要采用类型 2 和类型3 实现

 

 面向方面的编程,即 AOP,是一种编程技术,它允许程序员对横切关注点或横切典型的职责分界线的行为(例如日志和事务管理)进行模块化。AOP 的核心构造是方面,它将那些影响多个类的行为封装到可重用的模块中。

 

aop就是纵向的编程,如下图所示,业务1和业务2都需要一个共同的操作,与其往每个业务中都添加同样的代码,不如写一遍代码,让两个业务共同使用这段代码。


spring中面向切面变成的实现有两种方式,一种是动态代理,一种是CGLIB,动态代理必须要提供接口,而CGLIB实现是有继承。 

AOP(Aspect-OrientedProgramming)面向方面编程,与OOP完全不同,使用AOP编程系统被分为方面或关注点,而不是OOP中的对象。

 OOP面向对象的使用中,无可避免的会出现代码重复,而且使用面向对象的编程方式,这种重复无法避免,比如用户权限判断中,根据相应的权限执行相应的方法;在servlet中设置编码格式时,同样相同的代码出现很多次,而且还根业务无关,很容易忘记写,结果运行的时候就出现乱码拉。这种重复代码不仅使编码麻烦,而且还不容易维护。而AOP则将这些代码整理起来,将解决某个切面问题的代码单独的放在某个模块中,然后再织入到程序中。


AOP中的术语 

 Aspect:横切面的功能, 抽象出类,或接口, AOP编程重要的就是识别出横切面功能。(方面,类似于字符编码功能) 

 

 Advice: 横切面功能的具体实现,需要根据实际的情况分析,如果在目标对象操作之前是 before在操作之后,就是 afteradvice(增强,类似于字符编码过滤器)

 

 Pointcut:切入点,描述横切面功能应用的限制,不是所有的流程都需要,那些可以使用的地方就是切入点(类似于过滤器的匹配规则 /*)

 

 Joinpoint: 连接点,或指组件加入流程的时机,比如设置属性,调用方法,等,Spring只支持方法调用的连接点,而其他的一些框架支持属性的连接点如:AspectJ,(类似于过滤器的过滤规则 REQUEST,FORWARD)

 

 Weave: 缝合,将组件应用到业务流程中的这个过程,叫缝合或织入。

      (类似于将过滤器配置到web.xml文件的过程)

 

 Proxy,代理,在实现上,Spring的AOP其实就是使用JDK的动态代理(使用接口的方式完成代理操作),也可以使用CGLIB(使用继承的方式完成代理操作)。

 

 Target,目标,业务操作的实际对象


实例:设置字符编码格式看作是一个Aspect方面,而拦截器就是一个Advice增强。

<span style="font-size:18px;"><!-- 字符编码过滤器-->  
<filter>  
<filter-name>characterFilter</filter-name>  
<filter-class>com.bjpowernode.egov.filter.CharacterEncodingFilter</filter-class>  
</filter>  
<filter-mapping>  
<filter-name>characterFilter</filter-name>  
<url-pattern>/servlet/*</url-pattern>  
</filter-mapping>  
 </span>  

过滤器类

<span style="font-size:18px;">public class CharacterEncodingFilter implements Filter {  
   
   @Override  
   public void destroy() {}  
   
   @Override  
   public void doFilter(ServletRequest request, ServletResponse response,  
      FilterChainchain) throws IOException, ServletException {  
           request.setCharacterEncoding("GB18030");  
           chain.doFilter(request,response);  
   }  
   
   @Override  
   publicvoid init(FilterConfig filterConfig) throws ServletException {}  
}</span>  
 


这样就不用在每个servlet中设置编码拉。。

 

spring框架中AOP的使用

1,拷贝jar包

2,spring配置文件中增加命名空间和约束文件

启用aop功能:就把标签添加进来就可以拉。

3,写被代理的类和扩展类

4,由配置文件声明

<!--声明目标类-->  
<bean id="targetclass" class="com.spring.aop.TargetClass"></bean>  
<!--声明扩展类-->  
<bean id="extendsclass" class="com.spring.aop.extendsClass"></bean>  
<!--织入扩展类,并声明在哪个方法上执行扩展类-->  
<aop:config>  
    <aop:aspect id="extendAspect" ref="">  
        <aop:pointcut expression="execution(public ** (..))" id="extendsPoincat">  
        <!--在目标方法执行前执行的方法-->  
        <aop:before method="beforemethod" pointcut-ref="extendsPoincat" />  
        <!--在目标方法执行后执行的方法-->  
        <aop:after method="aftermethod" pointcut-ref="extendsPoincat" />  
    </aop:aspect>  
</aop:config></span>  

5,测试

 成功的话,执行目标类中的目标方法targetmethod()时,会先执行扩展类中的beforemethod()方法,再执行目标方法,最后再执行aftermethod()方法。

 也就是我们只需要手动调用targetmethod方法,扩展类中的两个方法框架会在执行的时候通过读取配置文件,获取相应信息,自动给我们添加上扩展的方法。。

 测试肯定成功,不相信的话,可以自己试试。

 

Spring框架中使用AOP的优点

   Aop与spring的IOC容器整合,增强,切入点都是javabean,可以在同一文件中配置和spring的其他部分一样,可以在不同应用服务器之间任意移植

   spring实现Aop的拦截接口,使得用户不必绑定在特定的拦截器接口上。

 aop面向切面的编程思想,打破面向对象的思维方式,我们要学习的不仅是aop的使用,更要学习面向切面的这种思想。

 

AOP 和 IOC 是补充性的技术,它们都运用模块化方式解决企业应用程序开发中的复杂问题。在典型的面向对象开发方式中,可能要将日志记录语句放在所有方法和 Java 类中才能实现日志功能。在 AOP 方式中,可以反过来将日志服务模块化,并以声明的方式将它们应用到需要日志的组件上。当然,优势就是 Java 类不需要知道日志服务的存在,也不需要考虑相关的代码。所以,用 Spring AOP 编写的应用程序代码是松散耦合的。AOP 的功能完全集成到了 Spring 事务管理、日志和其他各种特性的上下文中。

 

IOC 容器:Spring 设计的核心是 org.springframework.beans 包,它的设计目标是与 JavaBean 组件一起使用。这个包通常不是由用户直接使用,而是由服务器将其用作其他多数功能的底层中介。下一个最高级抽象是 BeanFactory 接口,它是工厂设计模式的实现,允许通过名称创建和检索对象。BeanFactory 也可以管理对象之间的关系。

 

spring 的容器

spring 管理的基本单元是Bean,在spring 的应用中,所有的组件都是一个个的Bean,它可以是任何的java 对象。spring 负责创建这些Bean的实例。并管理生命周期。而spring 框架是通过其内置的容器来完成Bean 的管理的,Bean 在spring 的容器中生存着,使用时只需要通过它提供的一些方法从其中获取即可。

spring 的容器有两个接口:BeanFactory 和ApplicationContext 这两个接口的实例被陈为spring 的上下文。

 

ApplicationContext ac = newClassFathXmlApplicationContext("app*.xml");  

AccountService accountService =(AccountService)ac.getBean("accountServiceImpl");</span>  

 

注:由于ApplicationContext是基于BeanFactory之上的,所以,一般ApplicationContext功能比较强大,建议使用ApplicationContext经常用到的三个实现:

1.ClassPathXmlApplicationContext:从类路径中的XML文件载入上下文定义信息。把上下文定义文件当成类路径资源。

2.FileSystemXmlApplicationContext:从文件系统中的XML文件载入上下文定义信息。

3.XmlWebApplicationContext:从Web系统中的XML文件载入上下文定义信息。

 

BeanFactory 支持两个对象模型:

1.单态 模型提供了具有特定名称的对象的共享实例,可以在查询时对其进行检索。Singleton 是默认的也是最常用的对象模型。对于无状态服务对象很理想。

2. 原型 模型确保每次检索都会创建单独的对象。在每个用户都需要自己的对象时,原型模型最适合。

bean 工厂的概念是 Spring 作为 IOC 容器的基础。IOC 将处理事情的责任从应用程序代码转移到框架。正如我将在下一个示例中演示的那样,Spring 框架使用 JavaBean 属性和配置数据来指出必须设置的依赖关系。 

 

1 Spring中的事务处理

2 ioc容器在Web容器中的启动

3 Spring JDBC

4 Spring MVC

5 Spring AOP获取Proxy

6 Spring声明式事务处理

7 Spring AOP中对拦截器调用的实现

8 Spring驱动Hibernate的实现

9 Spring Acegi框架鉴权的实现

 

spring的实例

第 1 步:创建 Java 项目

第 2 步:添加必需的库

第 3 步:创建源文件

 HelloWorld.java 和 MainApp.java 文件

这里是 HelloWorld.java 文件的内容:

package com.tutorialspoint;
public class HelloWorld {
   private String message;
   public void setMessage(Stringmessage){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("YourMessage : " + message);
   }
}

下面是第二个文件 MainApp.java 的内容:

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public staticvoid main(String[] args) {
      ApplicationContext context =
             newClassPathXmlApplicationContext("Beans.xml");
      HelloWorld obj = (HelloWorld)context.getBean("helloWorld");
      obj.getMessage();
   }
}

第 4 步:创建 bean 的配置文件

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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<beanid="helloWorld"class="com.tutorialspoint.HelloWorld">
       <propertyname="message" value="Hello World!"/>
  </bean>
</beans>

第 5 步:运行程序

 

自己动手模拟一个spring

首先我们把我们用的dao、service、entity定义出来:

Student.java :

public class Student{
 
    private int number;
    private String name;
    private String address;
 
    //get set 省略
}

因为spring提倡的就是面向接口编程,所以在我们写dao层和service层具体实现之前,我们先定义接口,让我们的具体实现实现接口。接口的代码很简单,在这就不贴出来了。

StudentNewDaoImp .java  

public classStudentNewDaoImp implements StudentNewDao {
 
  public void add(Student stu) {
    System.out.println("stuDao is set andsaved");
  }
}<span style="color: red; font-family: "Microsoft YaHei";font-size:14px; background-color: rgb(255, 255, 255);"> </span>

StudentServiceImp.java

public classStudentServiceImp implements StudentService {
  //定义dao的实例 没有new出来
  StudentNewDao stuDao=null;
 
  public StudentNewDao getStuDao() {
    return stuDao;
  }
 
  public void setStuDao(StudentNewDao stuDao) {
    this.stuDao = stuDao;
  }
 
  @Override
  public void add(Student stu) {
    stuDao.add(stu);
  }
 
}

      这里要注意的是,我们这里是模拟spring,主要模拟spring中的IOC功能,所以在此我们一样要在service层中定义dao的实例,当然不用new出来,我们就通过spring的IOC把这里的dao层注入进来

不要忘了对dao提供set。Get方法,因为IOC的底层其实就是利用反射机制实现的,他把dao注入进来,其实底层就是通过反射set进来的。

      好了,我们所需的dao层、service层还有entity定义好了之后,万事俱备只欠东风了,下一步我们就是定义我们自己的ClassPathXmlApplicationContext类了,通过他,在我们new出他的对象的时候,他来加载配置文件,然后把我们的dao操作注入到我们的service层,

 

在spring中,ClassPathXmlApplicationContext类实现了BeanFactory接口,在此我们也定义一个BeanFactory接口,其实这个接口没什么具体的作用,我们就是为了来模拟spring。在定义这个接口和实现类之前,我们先来看一下我们所需的xml是怎么编写的,下面我们就具体来看一下beans.xml的配置:

Beans.xml:

<beans>  
<bean id="stuDao" class="com.bzu.dao.imp.StudentDaoImp" />  
<bean id="stuService" class="com.bzu.service.imp.StudentServiceImp" >  
<property name="stuDao" bean="stuDao"/>  
</bean>  
</beans>  <span style="font-family: "Microsoft YaHei";font-size:14px; background-color: rgb(255, 255, 255);"> </span>

      看到这,相信大家都能感觉到这个配置文件太简单了,没有spring中那么多繁琐的配置,当然啦,我们这是只是实现其中的一个功能,spring提供了很多那么强大的功能,配置当然繁琐一些了。相信上边的代码不用我解释大家也能看懂了吧。

      好了,配置文件我们看完了,下一步我们一起来看一下我们的spring容器——

 

ClassPathXmlApplicationContext具体是怎么实现的,

我们首先还是来看一下他的接口定义:

BeanFactory.java:

public interface BeanFactory {  
public Object getBean(String id);  
}  

我们看到,接口其实很简单,就定义了一个getBean方法,下面我们来看一下具体的实现类:

ClassPathXmlApplicationContext.java

 

public classClassPathXmlApplicationContext implements BeanFactory {
 
    private Map<String, Object> beans =new HashMap<String, Object>();
 
    public ClassPathXmlApplicationContext()throws Exception, Exception {
        //把xml中的bean解析出来
        SAXBuilder sb = new SAXBuilder();
        Document doc =sb.build(this.getClass().getClassLoader().getResourceAsStream("beans.xml"));//构造文档对象
        Element root = doc.getRootElement(); //获取根元素HD
        List list =root.getChildren("bean");// 取名字为disk的所有元素
 
        for (int i = 0; i < list.size();i++) {
 
            Element element = (Element)list.get(i);
            String id =element.getAttributeValue("id");
            String clazz =element.getAttributeValue("class");
            Object o =Class.forName(clazz).newInstance();
            System.out.println(id + " :" + clazz);
 
            beans.put(id, o);
            for (Element propertyElement :(List<Element>) element.getChildren("property")) {
                String name =propertyElement.getAttributeValue("name"); // userDAO stuDao
                String bean =propertyElement.getAttributeValue("bean"); // u       stuDao
                Object beanObject =beans.get(bean);// UserDAOImpl instance  com.bzu.dao.StudentNewDaoImp
                System.out.println("Object: " + beanObject.getClass().getSimpleName());
 
                String methodName ="set" + name.substring(0, 1).toUpperCase()
                        + name.substring(1);
                System.out.println("methodname = " + methodName); //设置stuDao变为setStuDao  从而反射获得这个函数
 
                Method m =o.getClass().getMethod(methodName,
                       beanObject.getClass().getInterfaces()[0]);
                System.out.println("methodname = " + m.getName());
                m.invoke(o, beanObject);
            }
        }
    }
 
    @Override
    public Object getBean(String id) {
        return beans.get(id);
    }
}

解释一下这段代码: 

     首先我们定义了一个容器Map<String, Object> beans,这个容器的作用就是用来装我们从配置文件里解析来的一个个bean,为什么要用map类型,我想大家也差不多能猜到吧,我们配置文件中每一个bean都有一个id来作为自己的唯一身份。我们把这个id存到map的key里面,然后value就装我们的具体bean对象。

       说完这个容器之后,下面我们在来看一下ClassPathXmlApplicationContext的构造方法,这个构造方法是我们spring管理容器的核心,这个构造方法的前半部分是利用的jdom解析方式,把xml里面的bean一个个的解析出来,然后把解析出来的bean在放到我们bean容器里。

        我们下面在来看一下这个构造的方法,后半部分主要是在对配置文件进行解析出bean的同时去查看一下这个bean中有没有需要注射bean的,如果有的话,他就去通过这些里面的property属性获取他要注射的bean名字,然后构造出set方法,然后通过反射,调用注入bean的set方法,这样我们所需要的bean就被注入进来了。如果这段代码你看不懂的话,那你只能去看一下有关反射的知识了。最后我们就来看一下实现接口的getBean放了,其实这个方法很简单,就是根据提供的bean的id,从bean容器内把对应的bean取出来。

好了,我们所需的东西都定义好了,下面我们据来测试一下,看看我们自己模仿的spring到底能不能自动把我们所需要的dao层给我们注入进来。

public class Test {
 
    public static void main(String[] args)throws Exception {
 
        ClassPathXmlApplicationContext context= new ClassPathXmlApplicationContext();
        Student stu = new Student();
        StudentService service =(StudentService) context.getBean("stuService");
 
 //作用同上 实例化一个service然后service设置一个实例化的StuDao
//    StudentServiceImp service = newStudentServiceImp();
//    service.setStuDao(new StudentNewDaoImp());
 
        service.add(stu);
    }
}


运行代码,控制台输出:

stuDao :com.bzu.dao.StudentNewDaoImp

stuService :com.bzu.service.StudentServiceImp

Object :StudentNewDaoImp

method name =setStuDao

method name =setStuDao

stuDao is set andsaved

      好,成功注入进来,到此,我们模仿的spring就到此结束了,下一篇我们就开始对spring进行一个全面深入了解了,敬请期待。

 

一:spring 的依赖注入

1)、构造器注入

<bean id="accoutDaoImpl" class="cn.csdn.dao.AccoutDaoImpl"  scope=”singleton”/>  
<bean id="accoutServicImpl"  class="cn.csdn.service.AccoutServicImpl" scope=”">  
<!-- 构造方法注入方式-->  
<constructor-arg ref="accoutDaoImpl"/>  
</bean></span>  

注:这种注入方式很少用,如果是注入对象一般为上例注入,但有时要注入基本数据类型,一般用下面方法注入

<constructor-arg>  
<value>hello world!</value>  
</constructor-arg></span>  

如果构造方法不只一个参数时,应指明所注入参数的索引或者数据类型,例如:

<constructor-arg index="0" type="java.lang.String">  
<value>sunDriver</value>  
</constructor-arg>  
<constructor-arg index="1" type="java.lang.String">  
<value>jdbc:odbc:School</value>  
</constructor-arg></span>  

2)、设值(set 方法)注入

<bean id="accountDaoImpl"  
class="cn.csdn.dao.AccoutDaoImpl"/>  
<bean id="accoutServicImpl"  
class="cn.csdn.service.AccoutServicImpl">  
<!-- 设值(set 方法)注入-->  
<property name="accountDaoImpl" ref="accoutDaoImpl"/>  
</bean></span>  

注:<property name="accountDaoImpl" ref="accoutDaoImpl"/>

相当于调用set AccountDaoImpl方法,把值设为accoutDaoImpl

3)接口注入(很少用)

 

二: xml 装配Bean属性含义

1.id:指定该Bean 的唯一标识。

2.class:指定该Bean 的全限定名。

3.name:为该Bean 指定一到多个别名。多个别名可以用“,”和“;”分割。

4.autowire:指定该Bean 的属性的装配方式

所谓自动装配是指在<BEAN>标签中不用指定其依赖的BEAN,而是通过配置的自动装配来自动注入依赖的BEAN,这种做法让我们的配置更加简单。

1)no:不使用自动装配。必须通过ref 元素指定依赖,这是默认设置。由于显式指定协作者可以使配置更灵活、更清晰,因此对于较大的部署配置,推荐采用该设置。而且在某种程度上,它也是系统架构的一种文档形式。

<bean id="bean1" class="cn.csdn.service.Bean1"  
scope="singleton">  
<property name="studentDaoImpl"  
ref="studentDaoImpl">  
</property>  
</bean></span>  

备注:有property 属性指定ref

2)byName:根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。

例如,在bean 定义中将autowire设置为by name,而该bean 包含master 属性(同时提供setMaster(..)方法),Spring 就会查找名为master 的bean 定义,并用它来装配给master 属性。

<bean id="bean1" class="cn.csdn.service.Bean1"
scope="singleton" autowire="byName"/>

备注:没有property 属性

3)byType:如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType 方式进行自动装配。若没有找到相匹配的bean,则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置dependency-check="objects"让Spring 抛出异常。

备注:spring3.0 以上不抛异常。

<bean id="bean1" class="cn.csdn.service.Bean1"
scope="singleton" autowire="byType"/>

备注:没有property 属性

4)Constructor:与byType 的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。

<bean id="bean1" class="cn.csdn.service.Bean1"
scope="singleton"autowire="constructor"/>

备注:没有property 属性

5)autodetect:通过bean 类的自省机制(introspection)来决定是使用constructor 还是byType 方式进行自动装配。如果发现默认的构造器,那么将使用byType 方式。

<bean id="bean1" class="cn.csdn.service.Bean1"
scope="singleton" autowire="autodetect"/>

5.scope:指定该Bean 的生存范围 

scope用来声明IOC容器中的对象应该处的限定场景或者说该对象的存活空间,即在IOC容器在对象进入相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁这些对象。

1) singleton类型的bean定义,在一个容器中只存在一个实例,所有对该类型bean的依赖都引用这一单一实例

2) scope为prototype的bean,容器在接受到该类型的对象的请求的时候,会每次都重新生成一 个新的对象给请求方,虽然这种类型的对象的实例化以及属性设置等工作都是由容器负责的,但是只要准备完毕,并且对象实例返回给请求方之后,容器就不在拥有 当前对象的引用,请求方需要自己负责当前对象后继生命周期的管理工作,包括该对象的销毁

3) request ,session和global session

这三个类型是spring2.0之后新增的,他们只适用于web程序,通常是和XmlWebApplicationContext共同使用

request:

<bean id ="requestPrecessor" class="...RequestPrecessor"   scope="request" />

Spring容器,即XmlWebApplicationContext 会为每个HTTP请求创建一个全新的RequestPrecessor对象,当请求结束后,,该对象的生命周期即告结束

session

<bean id ="userPreferences" class="...UserPreferences"   scope="session" />

Spring容器会为每个独立的session创建属于自己的全新的UserPreferences实例,他比request scope的bean会存活更长的时间,其他的方面真是没什么区别。

global session:

<bean id ="userPreferences" class="...UserPreferences"   scope="globalsession" /> 

global session只有应用在基于porlet的web应用程序中才有意义,他映射到porlet的global范围的session,如果普通的servlet的web 应用中使用了这个scope,容器会把它作为普通的session的scope对待。

 

6.init-method:指定该Bean 的初始化方法。

destroy-method:指定该Bean 的销毁方法。

这个就像servlet中init和destroy方法一样,只不过这里在配置文件配置的

 

7.abstract:指定该Bean 是否为抽象的。如果是抽象的,则spring 不为它创建实例。

 

8.parent 

如果两个Bean 的属性装配信息很相似,那么可以利用继承来减少重复的配置工作。

<!-- 装配Bean 的继承
父类作为模板,不需要实例化,设置abstract=”true”-->
  <bean id=”parent” class=”cn.csdn.service.Parent”abstract=”true”>
<property name=”name” value=”z_xiaofei168”/>
<property name=”pass” value=”z_xiaofei168”/>
</bean>
 
<!-- 装配Bean 的继承子类中用parent 属性指定父类标识或别名
子类可以覆盖父类的属性装配,也可以新增自己的属性装配
-->
` <bean id=”child” class=”cn.csdn.service.Chlid” parent=”parent”>
<property name=”pass” value=”123123”/>
<property name=”age” value=”22”/>
</bean>

三:装配Bean 的各种类型属性值

1..简单类型属性值的装配

<bean id="bean1" class="cn.csdn.domain.Bean1">  
<property name="name" value="z_xiaofei168"/>  
<property name="age">  
<value>22</value>  
</property>  
</bean></span>  
2.引用其他Bean 的装配
<bean id="bean1" class="cn.csdn.domain.Bean1">  
...  
</bean>  
<bean id="bean2" class="cn.csdn.domain.Bean2">  
<!-- 引用自其他Bean 的装配-->  
<property name="bean1" ref="bean1"/>  
</bean></span>  
另外一种不常使用的配置方式是在property 元素中嵌入

一个bean 元素来指定所引用的Bean.

<bean id="bean1" class="cn.csdn.domain.Bean1">  
...  
</bean>  
<bean id="bean2" class="cn.csdn.domain.Bean2">  
<!-- 引用自其他Bean 的装配-->  
<property name="bean1">  
<bean id="bean1"  
class="cn.csdn.domain.Bean1"/>  
</property>  
</bean></span>  

3.集合的装配

其实集合的装配并不是复杂,反而感觉到很简单,用一个例子来说明问题吧:

 

四:Spring bean生命周期

    在传统的Java应用中,Bean的生命周期非常简单。 Java的关键词new用来实例化Bean(或许他是非序列化的)。这样就够用了。 相反,Bean的生命周期在Spring容器中更加细致。 理解Spring Bean的生命周期非常重要,因为你或许要利用Spring提供的机会来订制Bean的创建过程。 

 bean生命周期

1.容器寻找Bean的定义信息并且将其实例化。 

2.受用依赖注入,Spring按照Bean定义信息配置Bean的所有属性。 

3.如果Bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。 

4.如果Bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。 

5.如果BeanPostProcessor和Bean关联,那么它们的postProcessBeforeInitialzation()方法将被调用。 

6.如果Bean指定了init-method方法,它将被调用。 

7.最后,如果有BeanPsotProcessor和Bean关联,那么它们的postProcessAfterInitialization()方法将被调用。 

到这个时候,Bean已经可以被应用系统使用了,并且将被保留在Bean Factory中知道它不再需要。 

 

有两种方法可以把它从Bean Factory中删除掉。 

1.如果Bean实现了DisposableBean接口,destory()方法被调用。 

2.如果指定了订制的销毁方法,就调用这个方法。 

 

Bean在Spring应用上下文的生命周期与在Bean工厂中的生命周期只有一点不同, 唯一不同的是,如果Bean实现了ApplicationContextAwre接口,setApplicationContext()方法被调用。 

只有singleton行为的bean接受容器管理生命周期。 

non-singleton行为的bean,Spring容器仅仅是new的替代,容器只负责创建。 

对于singleton bean,Spring容器知道bean何时实例化结束,何时销毁, Spring可以管理实例化结束之后,和销毁之前的行为,管理bean的生命周期行为主要未如下两个时机: 

Bean全部依赖注入之后 

Bean即将销毁之前 

1)依赖关系注入后的行为实现: 

有两种方法:A.编写init方法  B.实现InitializingBean接口 

afterPropertiesSet和init同时出现,前者先于后者执行,使用init方法,需要对配置文件加入init-method属性 

2)bean销毁之前的行为 

有两种方法:A.编写close方法  B.实现DisposableBean接口 

destroy和close同时出现,前者先于后者执行,使用close方法,需要对配置文件加入destroy-method属性 

 总体上分只为四个阶段  

 1. BeanFactoyPostProcessor实例化  

 2. Bean实例化,然后通过某些BeanFactoyPostProcessor来进行依赖注入  

 3. BeanPostProcessor的调用.Spring内置的BeanPostProcessor负责调用Bean实现的接口: BeanNameAware, BeanFactoryAware, ApplicationContextAware等等,等这些内置的BeanPostProcessor调用完后才会调用自己配置的BeanPostProcessor  

 4.Bean销毁阶段  

注:xml依赖注入中的bean.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-2.5.xsd">  
  <bean id="u" class="com.bjsxt.dao.impl.UserDAOImpl">  
  </bean>  
  <bean id="userService" class="com.bjsxt.service.UserService">  
    <!--  
    <property name="userDAO" ref="u" /> 
     -->  
     <constructor-arg>  
        <ref bean="u"/>  
     </constructor-arg>  
  </bean>  
</beans></span>  

 

五:Spring注解

1.准备工作

(1)导入common-annotations.jar

(2)导入schema文件 文件名为spring-context-2.5.xsd

(3)在xml的beans节点中配置

 

2.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-2.5.xsd  
            http://www.springframework.org/schema/context  
            http://www.springframework.org/schema/context/spring-context-2.5.xsd"  
default-default-lazy-init="true">  
 <!--将针对注解的处理器配置好  -->     
 <context:annotation-config />     
 <!-- 使用annotation定义事务-->  
<tx:annotation-driventransaction-managertx:annotation-driventransaction-manager="transactionManager" proxy-target-class="true"/>  
 <!--使用annotation 自动注册bean,并检查@Required,@Autowired的属性已被注入base-package为需要扫描的包(含所有子包)-->  
<context:component-scanbase-packagecontext:component-scanbase-package="com" />  
 .....     
 <beans>    

注:<context:component-scan base-package="*.*" />

 该配置隐式注册了多个对注解进行解析的处理器,如:

 AutowiredAnnotationBeanPostProcessor     

 CommonAnnotationBeanPostProcessor

 PersistenceAnnotationBeanPostProcessor   

 RequiredAnnotationBeanPostProcessor

 其实,注解本身做不了任何事情,和XML一样,只起到配置的作用,主要在于背后强大的处理器,其中就包括了<context:annotation-config/>配置项里面的注解所使用的处理器,所以配置了<context:component-scanbase-package="">之后,便无需再配置<context:annotation-config>

 

Autowired和resource

1.在java代码中使用@Autowired或@Resource注解方式进行装配 ,这两个注解的区别是:

@Autowired默认按类型装配,

@Resource默认按名称装配,当找不到名称匹配的bean才会按类型装配。

@Autowired一般装配在set方法之上,也可以装配在属性上边,但是在属性上边配置,破坏了java的封装,所以一般不建议使用。

@Autowired是根据类型进行自动装配的。如果当Spring上下文中存在不止一个所要装配类型的bean时,就会抛出BeanCreationException异常;如果Spring上下文中不存在所要装配类型的bean,也会抛出BeanCreationException异常。

我们可以使用@Qualifier配合@Autowired来解决这些问题。 

@Autowired    

public void setUserDao(@Qualifier("userDao") UserDao userDao) {     

   this.userDao = userDao;     

}    

这样,Spring会找到id为userDao的bean进行装配。

可能不存在UserDao实例

@Autowired(required = false)     

public void setUserDao(UserDao userDao) {     

    this.userDao = userDao;     

}    


2.@Resource(JSR-250标准注解,推荐使用它来代替Spring专有的@Autowired注解)

Spring 不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,

它们分别是@Resource、@PostConstruct以及@PreDestroy。

@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按byName自动注入罢了。

@Resource有两个属性是比较重要的,分别是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略

@Resource装配顺序

1 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常

2 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常

3 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常

4 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配(见2);如果没有匹配,则回退为一个原始类型(UserDao)进行匹配,如果匹配则自动装配;

 

3. @PostConstruct(JSR-250)

在方法上加上注解@PostConstruct,这个方法就会在Bean初始化之后被Spring容器执行(注:Bean初始化包括,实例化Bean,并装配Bean的属性(依赖注入))。

它的一个典型的应用场景是,当你需要往Bean里注入一个其父类中定义的属性,而你又无法复写父类的属性或属性的setter方法时,如:

public class UserDaoImpl extends HibernateDaoSupport implements UserDao {     
 private SessionFactory mySessionFacotry;     
@Resource    
public void setMySessionFacotry(SessionFactory sessionFacotry) {     
    this.mySessionFacotry = sessionFacotry;     
   }     
  @PostConstruct    
   public void injectSessionFactory() {     
      super.setSessionFactory(mySessionFacotry);     
    }   }    

这里通过@PostConstruct,为UserDaoImpl的父类里定义的一个sessionFactory私有属性,注入了我们自己定义的sessionFactory(父类的setSessionFactory方法为final,不可复写),之后我们就可以通过调用super.getSessionFactory()来访问该属性了。

 

4.@PreDestroy(JSR-250)

在方法上加上注解@PreDestroy,这个方法就会在Bean初始化之后被Spring容器执行。由于我们当前还没有需要用到它的场景,这里不不去演示。其用法同@PostConstruct。

5.使用Spring注解完成Bean的定义

以上我们介绍了通过@Autowired或@Resource来实现在Bean中自动注入的功能,下面我们将介绍如何注解Bean,从而从XML配置文件中完全移除Bean定义的配置。

@Component:只需要在对应的类上加上一个@Component注解,就将该类定义为一个Bean了:

@Component    

public class UserDaoImpl extends HibernateDaoSupport implements UserDao {     

    ...     

}    

使用@Component注解定义的Bean,默认的名称(id)是小写开头的非限定类名。如这里定义的Bean名称就是userDaoImpl。你也可以指定Bean的名称:

@Component("userDao")

@Component是所有受Spring管理组件的通用形式,Spring还提供了更加细化的注解形式:@Repository、@Service、@Controller,它们分别对应存储层Bean,业务层Bean,和展示层Bean。目前版本(2.5)中,这些注解与@Component的语义是一样的,完全通用,在Spring以后的版本中可能会给它们追加更多的语义。所以,我们推荐使用@Repository、@Service、@Controller来替代@Component。

 

@Required

@Required注解应用于 bean 属性的 setter 方法。

@Autowired

@Autowired注解可以应用到 bean 属性的 setter 方法,非 setter 方法,构造函数和属性。

@Qualifier

通过指定确切的将被连线的bean,@Autowired 和 @Qualifier 注解可以用来删除混乱。

JSR-250 Annotations

Spring 支持JSR-250 的基础的注解,其中包括了 @Resource,@PostConstruct 和 @PreDestroy 注解。

 

基于 Java 的配置

到目前为止,你已经看到如何使用XML 配置文件来配置 Spring bean。如果你熟悉使用 XML 配置,那么我会说,不需要再学习如何进行基于 Java的配置是,因为你要达到相同的结果,可以使用其他可用的配置。

基于 Java的配置选项,可以使你在不用配置 XML 的情况下编写大多数的 Spring,但是一些有帮助的基于 Java 的注解,解释如下:

@Configuration 和 @Bean 注解

带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean定义的来源。@Bean 注解告诉 Spring,一个带有 @Bean的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。最简单可行的 @Configuration 类如下所示:

package com.tutorialspoint;
importorg.springframework.context.annotation.*;
@Configuration
public class HelloWorldConfig {
   @Bean 
   public HelloWorldhelloWorld(){
      return newHelloWorld();
   }
}

上面的代码将等同于下面的 XML配置:

<beans>
   <bean id="helloWorld"class="com.tutorialspoint.HelloWorld" />
</beans>

在这里,带有 @Bean注解的方法名称作为 bean 的 ID,它创建并返回实际的 bean。你的配置类可以声明多个 @Bean。

@Import 注解:

@import 注解允许从另一个配置类中加载 @Bean 定义。考虑 ConfigA类,如下所示:

@Configuration
public class ConfigA {
   @Bean
   public A a() {
      return new A(); 
   }
}

你可以在另一个 Bean声明中导入上述 Bean 声明,如下所示:

@Configuration
@Import(ConfigA.class)
public class ConfigB {
   @Bean
   public B a() {
      return new A(); 
   }
}

现在,当实例化上下文时,不需要同时指定ConfigA.class 和 ConfigB.class,只有 ConfigB 类需要提供,如下所示:

public static void main(String[] args){
   ApplicationContext ctx = 
   newAnnotationConfigApplicationContext(ConfigB.class);
  // now both beans A and B will be available...
   A a =ctx.getBean(A.class);
   B b = ctx.getBean(B.class);

6.使用<context:component-scan />让Bean定义注解工作起来 

切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。

事务管理是J2EE应用中一个关于横切关注点的很好的例子。

在Spring AOP中,切面可以使用基于模式)或者基于Aspect注解方式来实现。通俗点说就是我们加入的切面类(比如log类),可以这么理解。

 

连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。通俗的说就是加入切点的那个点

 

通知(Advice):在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。

 

切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。

 

引入(Introduction):用来给一个类型声明额外的方法或属性(也被称为连接类型声明(inter-type declaration))。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用引入来使一个bean实现IsModified接口,以便简化缓存机制。

 

目标对象(Target Object): 被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。

 

AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。

 

织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

 

通知类型:

前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。

后置通知(After returning advice):在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。

异常通知(After throwing advice):在方法抛出异常退出时执行的通知。

最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

环绕通知(Around Advice):包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。

环绕通知是最常用的通知类型。和AspectJ一样,Spring提供所有类型的通知,我们推荐你使用尽可能简单的通知类型来实现需要的功能。例如,如果你只是需要一个方法的返回值来更新缓存,最好使用后置通知而不是环绕通知,尽管环绕通知也能完成同样的事情。用最合适的通知类型可以使得编程模型变得简单,并且能够避免很多潜在的错误。比如,你不需要在JoinPoint上调用用于环绕通知的proceed()方法,就不会有调用的问题。


  1)IoC(Inversion ofControl)控制反转,对象创建责任的反转,在spring中BeanFacotory是IoC容器的核心接口,负责实例化,定位,配置应用程序中的对象及建立这些对象间的依赖。XmlBeanFacotory实现BeanFactory接口,通过获取xml配置文件数据,组成应用对象及对象间的依赖关系。

spring中有三种注入方式,一种是set注入,一种是接口注入,另一种是构造方法注入。

  

3,为什么使用spring框架

 在不使用spring框架之前,我们的service层中要使用dao层的对象,不得不在service层中new一个对象。如下:

//dao层对象  
public class UserDao{  
   publicvoid insert(User user){}  
}  
   
//service层对象  
public classUserService{  
   publicvoid insert(User user){  
       UserDaouserdao = new UserDao();  
       userdao.insert(user);  
   }  
}  

存在的问题:层与层之间的依赖。

使用框架后:

//dao层对象  
public class UserDao{  
    publicvoid insert(User user){}  
}  
   
//service层对象  
public classUserService{  
   privateUserDao userdao;  
   
   publicUserDao getUserdao() {  
      returnuserdao;  
   }  
   publicvoid setUserdao(UserDao userdao) {  
      this.userdao= userdao;  
   }  
   
   publicvoid insert(User user){  
      userdao.insert(user);  
   }  
}  

service层要用dao层对象需要配置到xml配置文件中,至于对象是怎么创建的,关系是怎么组合的都交给了spring框架去实现。

 

4,框架优点

轻量级的容器框架没有侵入性

使用IoC容器更加容易组合对象直接间关系,面向接口编程,降低耦合

Aop可以更加容易的进行功能扩展,遵循ocp开发原则

创建对象默认是单例的,不需要再使用单例模式进行处理

5,缺点:业务功能依赖spring特有的功能,依赖与spring环境。 

 

 spring框架为我们提供了三种注入方式,

分别是set注入,构造方法注入,接口注入。接口注入不作要求,下面介绍前两种方式。

1,set注入

 采用属性的set方法进行初始化,就成为set注入。

    1)给普通字符类型赋值。

public class User{  
   privateString username;  
   
   publicString getUsername() {  
       returnusername;  
   }  
   publicvoid setUsername(String username) {  
      this.username= username;  
   }  
}  <span style="font-family: "Microsoft YaHei";font-size:14px; background-color: rgb(255, 255, 255);"> </span>

  我们只需要提供属性的set方法,然后去属性文件中去配置好让框架能够找到applicationContext.xml文件的beans标签。标签beans中添加bean标签, 指定id,class值,id值不做要求,class值为对象所在的完整路径。bean标签再添加property 标签,要求,name值与User类中对应的属性名称一致。value值就是我们要给User类中的username属性赋的值。

<bean id="userAction"class="com.lsz.spring.action.User" >  
<span style="white-space:pre">  </span><property name="username" value="admin"></property>  
</bean>  
 

   2)给对象赋值

 同样提供对象的set方法

public class User{  
     private UserService userservice;  
     public UserServicegetUserservice() {  
          returnuser;  
     }  
     public void setUserservice(UserService userservice){  
         this.userservice= userservice;  
     }  
}  

  配置文件中要增加UserService的bean标签声明及User对象对UserService引用。

<!--对象的声明-->  
<bean id="userService" class="com.lsz.spring.service.UserService"></bean>  
<bean id="userAction"class="com.lsz.spring.action.User" >  
   <property name="userservice" ref="userService"></property>  
</bean>  

 这样配置,框架就会将UserService对象注入到User类中。

 

  3)给list集合赋值

 同样提供set方法

public class User{  
    privateList<String> username;  
    publicList<String> getUsername() {  
        returnusername;  
    }  
    publicvoid setUsername(List<String> username) {  
        this.username= username;  
    }  
}  

<bean id="userAction"class="com.lsz.spring.action.User" >  
     <propertynamepropertyname="username">  
           <list>  
               <value>zhang,san</value>  
               <value>lisi</value>  
               <value>wangwu</value>                                  
               </list>  
    </property>  
</bean>  

  4)给属性文件中的字段赋值

public class User{  
    privateProperties props ;  
    publicProperties getProps() {  
        returnprops;  
    }  
    publicvoid setProps(Properties props) {  
        this.props= props;  
    }  
}  

<bean>  
    <propertynamepropertyname="props">  
        <props>  
           <propkeypropkey="url">jdbc:oracle:thin:@localhost:orl</prop>  
           <propkeypropkey="driverName">oracle.jdbc.driver.OracleDriver</prop>  
           <propkeypropkey="username">scott</prop>  
           <propkeypropkey="password">tiger</prop>  
        </props>  
    </property>  
</bean>  
<prop>标签中的key值是.properties属性文件中的名称
 

注意:

 无论给什么赋值,配置文件中<property>标签的name属性值一定是和对象中名称一致。

 

2构造方法注入

   1)构造方法一个参数

public class User{  
    privateString usercode;  
    publicUser(String usercode) {  
        this.usercode=usercode;  
    }  
}  

<bean id="userAction"class="com.lsz.spring.action.User">                          
    <constructor-argvalueconstructor-argvalue="admin"></constructor-arg>                          
</bean>  

   2)构造函数有两个参数时

 当参数为非字符串类型时,在配置文件中需要制定类型,如果不指定类型一律按照字符串类型赋值。

 当参数类型不一致时,框架是按照字符串的类型进行查找的,因此需要在配置文件中制定是参数的位置

<constructor-argvalueconstructor-argvalue="admin"index="0"></constructor-arg>                  

<constructor-argvalueconstructor-argvalue="23" type="int"index="1"></constructor-arg>  

 这样制定,就是构造函数中,第一个参数为string类型,第二个参数为int类型

单元测试不是头一次听说了,但只是听说从来没有用过。一个模块怎么测试呢,是不是得专门为一单元写一个测试程序,然后将测试单元代码拿过来测试?我是这么想的。学到spring框架这才知道单元测试原来是这么回事儿。

 

  注解Annotation

是一种类似注释的机制,在代码中添加注解可以在之后某时间使用这些信息。跟注释不同的是,注释是给我们看的,java虚拟机不会编译,注解也是不编译的,但是我们可以通过反射机制去读取注解中的信息。注解使用关键字@interface,继承java.lang.annotition.Annotition

  spring框架为我们提供了注解功能。

 使用注解编程,主要是为了替代xml文件,使开发更加快速。但是,xml文件的使用就是解决修改程序修改源代码,现在又不去使用xml文件,那么不就违背了开闭原则了么,得确是。不过么,注解也有注解的好,使用注解就不用配置那么多的xml文件啦,最重要的是开发效率高。。

 在没有使用注解时,spring框架的配置文件applicationContext.xml文件中需要配置很多的<bean>标签,用来声明类对象。使用注解,则不必在配置文件中添加标签拉,对应的是在对应类的“注释”位置添加说明。

具体介绍如下: 

   spring框架使用的是分层的注解。

   持久层:@Repository;

   服务层:@Service

   控制层:@Controller

 

1,使用注解,需要在配置文件中增加命名空间和约束文件

<beans ...  
xmlns:context="http://www.springframework.org/schema/context"  
xsi:schemaLocation="  
...  
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd  
">  

2,告诉框架那些类是使用注解的。

<context:component-scanbase-package="com.lsz.spring" />

 

3,持久层注解

Package com.lsz.spring;  

@Repository  

public class UserDao{  

//。。。。  

}  

@Repository 等同于配置文件中的

<bean id="userDao" class="com.lsz.spring.UserDao" />  

 

4,服务层注解

@Service(value="testService")  
public classTestService {  
   
@Resource//相当于自动装配  
private UserDao userDao ;  
      public UserDao getUserDao() {  
              returnuserDao;  
      }  
      public void setUserDao(UserDao userDao) {  
             this.userDao= userDao;  
      }  
}  

@Resource 对象间关系的组合,默认采用的是byName方式进行装配,如果根据名称查找不到关联的对象,那么会再采用byType继续查找。

@Service注解等同与

<bean id="testService" class="com.lsz.spring.UserService" />  

 

5,控制层注解

@Controller(value="ua")  
@Scope(value="prototype")  
public class UserAction {  
   
     @Resource  
     private UserService userService ;  
   
     public UserService getUserService() {  
          returnuserService;  
     }  
}  

 @Controller注解等同于

<bean id="ua" class="com.lsz.spring.UserAction " />  

 这三个层中的注解关键字都可以使用@Component来代替。

 使用注解声明对象,默认情况下生成的id名称为类名称的首字母小写。

 

6,从Spring环境中获取Action对象。

ServletContext application =request.getSession().getServletContext();  
ApplicationContextac = WebApplicationContextUtils.getWebApplicationContext(application);  
   
UserAction useraction = (UserAction)ac.getBean("ua");//获取控制层对象  
  
response.setContentType("text/html;charset=GBK");//设置编码  
PrintWriter out =response.getWriter();  
  
//分别将三个层的对象打印出来。  
out.println("Action:"+userAction);  
out.println("Service:"+userAction.getUserService());  
out.println("Dao:"+userAction.getUserService().getUserDao()); 

 

Spring MVC

Hello World 例子

下面的例子说明了如何使用Spring MVC 框架来编写一个简单的基于 web 的 Hello World 应用程序。为了开始使用它,让我们在恰当的位置使用 EclipseIDE,然后按照下面的步骤使用 Spring 的 Web 框架来开发一个动态 Web 应用程序:

步骤

描述

1

创建一个名称为 HelloWeb 的动态 Web 项目,并且在已创建的项目的 src 文件夹中创建一个包com.tutorialspoint。

2

将上面提到的 Spring 和其他库拖拽到文件夹 WebContent/WEB-INF/lib 中。

3

在 com.tutorialspoint 包下创建一个 Java 类 HelloController。

4

在 WebContent/WEB-INF 文件夹下创建 Spring 的配置文件 Web.xml 和 HelloWeb-servlet.xml。

5

在 WebContent/WEB-INF 文件夹下创建名称为 jsp 的子文件夹。在这个子文件夹下创建一个视图文件hello.jsp。

6

最后一步是创建所有的源代码和配置文件的内容,并导出该应用程序,正如下面解释的一样。

这里是 HelloController.java 文件的内容:

package com.tutorialspoint;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.ui.ModelMap;
@Controller
@RequestMapping("/hello")
public class HelloController{ 
   @RequestMapping(method =RequestMethod.GET)
   public String printHello(ModelMapmodel) {
     model.addAttribute("message", "Hello Spring MVCFramework!");
      return "hello";
   }
}

下面是 Spring Web配置文件 web.xml 的内容

<web-app id="WebApp_ID"version="2.4"
  xmlns="http://java.sun.com/xml/ns/j2ee" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>SpringMVC Application</display-name>
<servlet>
     <servlet-name>HelloWeb</servlet-name>
      <servlet-class>
         org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
     <load-on-startup>1</load-on-startup>
   </servlet>
<servlet-mapping>
     <servlet-name>HelloWeb</servlet-name>
     <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

下面是另一个 SpringWeb 配置文件 HelloWeb-servlet.xml 的内容

<beansxmlns="http://www.springframework.org/schema/beans"
  xmlns:context="http://www.springframework.org/schema/context"
   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-3.0.xsd
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scanbase-package="com.tutorialspoint" />
<beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <propertyname="prefix" value="/WEB-INF/jsp/" />
      <property name="suffix"value=".jsp" />
   </bean>
</beans>

下面是 Spring视图文件 hello.jsp 的内容

<%@ page contentType="text/html;charset=UTF-8"%>
<html>
<head>
<title>HelloWorld</title>
</head>
<body>
   <h2>${message}</h2>
</body>
</html>


表单处理

下面是 StudentController.java 文件的内容:

package com.tutorialspoint;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.ui.ModelMap;
@Controller
public class StudentController {
   @RequestMapping(value= "/student", method = RequestMethod.GET)
   public ModelAndView student(){
      return newModelAndView("student", "command", new Student());
   }  
   @RequestMapping(value ="/addStudent", method = RequestMethod.POST)
   public StringaddStudent(@ModelAttribute("SpringWeb")Student student, 
   ModelMap model) {
      model.addAttribute("name",student.getName());
     model.addAttribute("age", student.getAge());
      model.addAttribute("id",student.getId());      
      return"result";
   }
}

在这里,第一个 service方法 student(),我们已经在名称为 “command” 的 ModelAndView对象中传递一个空的Student 对象,因为 spring 框架需要一个名称的 “command”的对象,如果你在 JSP 文件中使用 <form:form> 标签。所以,当 student() 方法被调用时,它返回 student.jsp 视图。

第二个 service方法 addStudent() 将调用 HelloWeb/addStudent URL 中的 POST方法。你将根据提交的信息准备好你的模型对象。最后一个 “result” 视图会从 service 方法中返回,它将导致呈现 result.jsp。

页面重定向

静态页面

异常处理

 

使用 Log4J 记录日志

在 Spring 应用程序中使用Log4J 的功能是非常容易的。下面的例子将带你通过简单的步骤解释 Log4J 和 Spring 之间的简单集成。

假设你已经在你的机器上安装了 Log4J,如果你还没有 Log4J,你可以从 http://logging.apache.org/ 中下载,并且仅仅在任何文件夹中提取压缩文件。在我们的项目中,我们将只使用 log4j-x.y.z.jar

接下来,我们让 EclipseIDE 在恰当的位置工作,遵循以下步骤,使用 Spring Web 框架开发一个基于 Web 应用程序的动态表单:

步骤

描述

1

创建一个名称为 SpringExample 的项目,并且在创建项目的 src 文件夹中创建一个包com.tutorialspoint。

2

使用 Add External JARs 选项,添加所需的 Spring 库,解释见 Spring Hello World Example 章节。

3

使用 Add External JARs 选项,同样在你的项目中添加 log4j 库 log4j-x.y.z.jar。

4

在 com.tutorialspoint 包下创建 Java 类 HelloWorld 和 MainApp。

5

在 src 文件中创建 Bean 配置文件 Beans.xml。

6

在 src 文件中创建 log4J 配置文件 log4j.properties。

7

最后一步是创建的所有 Java 文件和 Bean 配置文件的内容,并运行应用程序,解释如下所示。

这个是 HelloWorld.java 文件的内容:

package com.tutorialspoint;
public class HelloWorld {
   private String message;
   public void setMessage(Stringmessage){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("YourMessage : " + message);
   }
}
下面的是第二个文件  MainApp.java  的内容:

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
import org.apache.log4j.Logger;
public class MainApp {
   static Logger log =Logger.getLogger(MainApp.class.getName());
   public static void main(String[]args) {
      ApplicationContextcontext = 
             newClassPathXmlApplicationContext("Beans.xml");
      log.info("Going to createHelloWord Obj");
     HelloWorld obj = (HelloWorld)context.getBean("helloWorld");
      obj.getMessage();
      log.info("Exiting theprogram");
   }
}

使用与我们已经生成信息消息类似的方法,你可以生成调试错误消息。现在让我们看看 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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<beanid="helloWorld"class="com.tutorialspoint.HelloWorld">
       <propertyname="message" value="Hello World!"/>
  </bean>
</beans>

下面是 log4j.properties 的内容,它定义了使用 Log4J 生成日志信息所需的标准规则:

# Define the root logger with appenderfile
log4j.rootLogger = DEBUG, FILE

# Define the fileappender
log4j.appender.FILE=org.apache.log4j.FileAppender
# Set the name of the file
log4j.appender.FILE.File=C:\\log.out

# Set the immediate flush totrue (default)
log4j.appender.FILE.ImmediateFlush=true

# Set the threshold to debugmode
log4j.appender.FILE.Threshold=debug

# Set the append to false,overwrite
log4j.appender.FILE.Append=false

# Define the layout for fileappender
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern=%m%n

一旦你完成了创建源和 bean的配置文件后,我们就可以运行该应用程序。如果你的应用程序一切都正常,在 Eclipse 控制台将输出以下信息:

Your Message : Hello World!

同时如果你检查你的 C:\驱动,那么你应该发现含有各种日志消息的日志文件 log.out,其中一些如下所示:

<!-- initialization log messages -->

Going to create HelloWordObj
Returning cached instance of singleton bean 'helloWorld'
Exiting the program

Jakarta Commons Logging (JCL) API

或者,你可以使用 Jakarta CommonsLogging(JCL) API 在你的Spring 应用程序中生成日志。JCL 可以从http://jakarta.apache.org/commons/logging/ 下载。我们在技术上需要这个包的唯一文件是 commons-logging-x.y.z.jar 文件,需要使用与上面的例子中你使用 log4j-x.y.z.jar 类似的方法来把 commons-logging-x.y.z.jar 放在你的类路径中。

为了使用日志功能,你需要一个 org.apache.commons.logging.Log 对象,然后你可以根据你的需要调用任何一个下面的方法:

  • fatal(Object message)
  • error(Object message)
  • warn(Object message)
  • info(Object message)
  • debug(Object message)
  • trace(Object message)

下面是使用 JCL API 对MainApp.java 的替换:

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
importorg.springframework.context.support.ClassPathXmlApplicationContext;
import org.apache.commons.logging. Log;
import org.apache.commons.logging. LogFactory;
public class MainApp {
   static Log log =LogFactory.getLog(MainApp.class.getName());
   public static void main(String[]args) {
      ApplicationContextcontext = 
             newClassPathXmlApplicationContext("Beans.xml");
      log.info("Goingto create HelloWord Obj");
      HelloWorld obj = (HelloWorld)context.getBean("helloWorld");
      obj.getMessage();
      log.info("Exiting theprogram");
   }
}

你应该确保在编译和运行该程序之前在你的项目中已经引入了 commons-logging-x.y.z.jar 文件。

现在保持在上面的例子中剩下的配置和内容不变,如果你编译并运行你的应用程序,你就会得到与使用Log4J API 后获得的结果类似的结果。


文章参考其他博客;

http://wiki.jikexueyuan.com/project/spring/

http://blog.csdn.net/lishuangzhe7047/article/details/20740835

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值