疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

spring以及spring MVC


 

 

 

一.spring的核心模块

   Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:

       1)Spring Core:核心容器,BeanFactory提供了组件生命周期的管理,组件的创建,装配,销毁等功能

    SpringContext:ApplicationContext,扩展核心容器,提供事件处理、国际化等功能。它提供了一些企业级服务的功能,提供了JNDI,EJB,RMI的支持。

       2) Spring AOP:提供切面支持

       3) Spring DAO:提供事务支持,JDBC,DAO支持

       4) Spring ORM:对流行的O/R Mapping封装或支持

       5) Spring Web:提供Web应用上下文,对Web开发提供功能上的支持,如请求,表单,异常等。

       6) Spring Web MVC:全功能MVC框架,作用等同于Struts。

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

二.IOC的概念

控制反转(IOC):是面向对象编程中的一种设计原则,用来降低程序代码之间的耦合度,

         使整个程序体系结构更加灵活,与此同时将类的创建和依赖关系写在配置文件里,由配置文件注入,达到松耦合的效果。

         与此同时IOC也称为DI(依赖注入),依赖注入是一种开发模式;依赖注入提倡使用接口编程;

         依赖注入使得可以开发各个组件,然后根据组件之间的依赖关系注入组装。

2.2.IoC的类型

spring的注入方式:

      (1) 基于特定接口(侵入式方案)

      (2) 基于set方法:是容器通过调用无参构造器或无参static 工厂方法实列化bean之后,调用该bean的setter方法,    即实现了基于setter的依赖注入

      (3) 基于构造器:主要采用构造函数和构造器来进行注入

2.3.Spring容器

      Spring容器负责生成、组装、销毁组件,并负责事件处理、国际化等功能。

      (1) BeanFactory<interface>

        ① 核心容器,负责组件生成和装配

        ② 实现主要包括Xml BeanFactory

      (2) ApplicationContext

      (3) WebApplicationContext

      (4) ……

2.4IOC的使用

    Resource:interface,用来包装资源

    xmlBeanFactory:BeanFactory的一个实现,使用Resource对象来查找配置文件

    BeanFactory.gerBean(“BeanId”):取得以参数命名,或者Id等于参数值的一个Bean实例。

    BeanFactory(容器)在默认情况下,会采用单例方式返回对象。容器只到调用getBean方法时,才会实例化某个对象。

     (1) Spring可以采用XML或者.properties文件作配置

    (2) 配置文件(XML)

     根元素可以有多个子元素,每个代表一个需要装配的对象。

复制代码
public class HelloServiceTest {     @Test     public void testHelloWorld() {         // 1、读取配置文件实例化一个IOC容器
        ApplicationContext context = new ClassPathXmlApplicationContext("helloworld.xml");         // 2、从容器中获取Bean,注意此处完全“面向接口编程,而不是面向实现”
        HelloService helloService = context.getBean("helloService", HelloService.class);         // 3、执行业务逻辑
        helloService.sayHello();     } }
复制代码

 

三、AOP核心概念

  1、Aspect(切面)

  切面,是对交叉业务逻辑的统称。

  2、Joinpoint(连接点)

  连接点,指切面可以织入到目标对象的位置(方法,属性等)。

  3、Advice(通知)

  通知,指切面的具体实现。

  4、Pointcut(切入点)

  切入点,指通知应用到哪些类的哪些方法或属性之上的规则。

  5、Introduction(引入)

  引入,指动态地给一个对象增加方法或属性的一种特殊的通知。

  6、Weaving(织入)

  织入,指将通知插入到目标对象。

  7、Target(目标对象)

  目标对象,指需要织入切面的对象。

  8、Proxy(代理对象)

  代理对象,指切面织入目标对象之后形成的对象。

3.1.AOP的原理 

    Spring AOP采用动态代理的过程:

(1) 将切面使用动态代理的方式动态织入到目标对象(被代理类),形成一个代理对象;

(2) 目标对象如果没有实现代理接口,那么Spring会采用CGLib来生成代理对象,该代理对象是目标对象的子类;

(3) 目标对象如果是final类,并且也没实现代理接口,就不能运用AOP。

  AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:

1、定义普通业务组件

2、定义切入点,一个切入点可能横切多个业务组件

3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作

所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。

基于Spring的AOP简单实现

注意一下,在讲解之前,说明一点:使用Spring AOP,要成功运行起代码,只用Spring提供给开发者的jar包是不够的,请额外上网下载两个jar包:

1、aopalliance.jar

2、aspectjweaver.jar

先定义一个接口:

public interface HelloWorld {     void printHelloWorld();     void doPrint(); }

定义两个接口实现类:

复制代码
public class HelloWorldImpl1 implements HelloWorld {     public void printHelloWorld()     {         System.out.println("Enter HelloWorldImpl1.printHelloWorld()");     }          public void doPrint()     {         System.out.println("Enter HelloWorldImpl1.doPrint()");         return ;     } }
复制代码
复制代码
public class HelloWorldImpl2 implements HelloWorld {     public void printHelloWorld()     {         System.out.println("Enter HelloWorldImpl2.printHelloWorld()");     }          public void doPrint()     {         System.out.println("Enter HelloWorldImpl2.doPrint()");         return ;     } }
复制代码

横切关注点,这里是打印时间:

复制代码
public class TimeHandler {     public void printTime()     {         System.out.println("CurrentTime = " + System.currentTimeMillis());     } }
复制代码

有这三个类就可以实现一个简单的Spring AOP了,看一下aop.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:aop="http://www.springframework.org/schema/aop"     xmlns:tx="http://www.springframework.org/schema/tx"     xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler">
                <aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />

<!--第一个*表示匹配任意的方法返回值,第二个*表示所有方法,..表示方法的任意参数个数-->

                <aop:before method="printTime" pointcut-ref="addAllMethod" />
                <aop:after method="printTime" pointcut-ref="addAllMethod" />
            </aop:aspect>
        </aop:config>
</beans>
复制代码

使用一个main函数调用:

复制代码
public static void main(String[] args) {     ApplicationContext ctx = 
            new ClassPathXmlApplicationContext("aop.xml");              HelloWorld hw1 = (HelloWorld)ctx.getBean("helloWorldImpl1");     HelloWorld hw2 = (HelloWorld)ctx.getBean("helloWorldImpl2");     hw1.printHelloWorld();     System.out.println();     hw1.doPrint();          System.out.println();     hw2.printHelloWorld();     System.out.println();     hw2.doPrint(); }
复制代码

运行结果为:

复制代码
CurrentTime = 1446129611993 Enter HelloWorldImpl1.printHelloWorld() CurrentTime = 1446129611993  CurrentTime = 1446129611994 Enter HelloWorldImpl1.doPrint() CurrentTime = 1446129611994  CurrentTime = 1446129611994 Enter HelloWorldImpl2.printHelloWorld() CurrentTime = 1446129611994  CurrentTime = 1446129611994 Enter HelloWorldImpl2.doPrint() CurrentTime = 1446129611994
复制代码

Spring注意事项

Spring的日志输出是依赖于commons-logging,但是spring的jar包中没有给我们提供,所以我们需要自己进行下载。

Spring最主要的核心包是4个【 beans、context、core、expression】,一个简单的spring需要着5个jar包即可,如果要扩展功能的话,我们需要在源码的libs中再重新引入所需要的jar包。

Spring在连接数据库时,需要引入连接数据库的jar包,这个也需要我们另外下载

四.spring MVC

4.1.SpringMVC流程

1、  用户发送请求至前端控制器DispatcherServlet。

2、  DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、  处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、  DispatcherServlet调用HandlerAdapter处理器适配器。

5、  HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、  Controller执行完成返回ModelAndView。

7、  HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

8、  DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

9、  ViewReslover解析后返回具体View。

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、 DispatcherServlet响应用户。

4.2.组件:
1、前端控制器DispatcherServlet(不需要工程师开发),由框架提供
作用:接收请求,响应结果,相当于转发器,中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。

2、处理器映射器HandlerMapping(不需要工程师开发),由框架提供
作用:根据请求的url查找Handler
HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

4、处理器Handler(需要工程师开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler。

5、视图解析器View resolver(不需要工程师开发),由框架提供
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。

6、视图View(需要工程师开发jsp...)
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...)

4.3.springMVC-mvc.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:tx="http://www.springframework.org/schema/tx"       xmlns:context="http://www.springframework.org/schema/context"         xmlns:mvc="http://www.springframework.org/schema/mvc"         xsi:schemaLocation="http://www.springframework.org/schema/beans   
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
    http://www.springframework.org/schema/tx   
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context-3.0.xsd  
    http://www.springframework.org/schema/mvc  
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">  
  
  
    <!-- 自动扫描的包名 -->  
    <context:component-scan base-package="com.app,com.core,JUnit4" ></context:component-scan>  
      
    <!-- 默认的注解映射的支持 -->  
    <mvc:annotation-driven />  
      
    <!-- 视图解释类 -->  
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
        <property name="prefix" value="/WEB-INF/jsp/"/>  
        <property name="suffix" value=".jsp"/><!--可为空,方便实现自已的依据扩展名来选择视图解释类的逻辑  -->  
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />  
    </bean>  
      
    <!-- 拦截器 -->  
    <mvc:interceptors>  
        <bean class="com.core.mvc.MyInteceptor" />  
    </mvc:interceptors>       
      
    <!-- 对静态资源文件的访问  方案一 (二选一) -->  
    <mvc:default-servlet-handler/>  
      
    <!-- 对静态资源文件的访问  方案二 (二选一)-->  
    <mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>  
    <mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"/>  
    <mvc:resources mapping="/css/**" location="/css/" cache-period="31556926"/>  
  
</beans>   
复制代码

<context:component-scan/> 扫描指定的包中的类上的注解,常用的注解有:

@Controller 声明Action组件
@Service    声明Service组件    @Service("myMovieLister") 
@Repository 声明Dao组件
@Component   泛指组件, 当不好归类时. 
@RequestMapping("/menu")  请求映射
@Resource  用于注入,( j2ee提供的 ) 默认按名称装配,@Resource(name="beanName") 
@Autowired 用于注入,(srping提供的) 默认按类型装配 
@Transactional( rollbackFor={Exception.class}) 事务管理
@ResponseBody
@Scope("prototype")   设定bean的作用域

 

@ModelAtrribute的运行流程

1.执行@ModelAtrribute注解修饰的方法:从数据库中取出对象,并把对象放到了Map中,键为user

2.springMVC从Map集合中取出User对象,并把表单的请求参数赋值给user对象相应的属性

3.springMVC把上述对象传入目标方法的参数

4.这个user对象是存在request中,如果jsp表单中有对应的字段,还会自动填充表单

注意:在@ModelAtrribute修饰的方法中,放入Map时的键要和目标方法的参数名一致

 

4.4.Converter与Formatter

Spring的Converter可以将一种类型转换成另一种类型。
在使用时,必须编写一个实现org.springframework.core.convert.converter.Converter接口的java类。这个接口的声明如下

public interface Converter<S, T> {     T convert(S var1); }

这里的S表示源类型,T表示目标类型。
下面展示了一个将String类型转换成Date类型的Converter

复制代码
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.core.convert.converter.Converter;  import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date;  public class StringToDateConverter implements Converter<String, Date>{     private static final Log logger = LogFactory.getLog(StringToDateConverter.class);     private String datePattern;      public StringToDateConverter(String datePattern) {         this.datePattern = datePattern;     }      public Date convert(String s) {         try {             SimpleDateFormat dateFormat = new SimpleDateFormat(datePattern);             dateFormat.setLenient(false);             return dateFormat.parse(s);         } catch (ParseException e) {             throw new IllegalArgumentException("invalid date format. Please use this pattern"" + datePattern + """);         }     } }
复制代码

为了使用Spring MVC应用程序定制的Converter,需要在配置文件中添加一个conversionService bean。Bean的类名称必须为org.springframework.context.support.ConversionServiceFactoryBean。这个bean必须包含一个converters属性,它列出要在应用程序中使用的所有定制Converter。下面bean声明注册了上面StringToDateConverter。

复制代码
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="app06a.converter.StringToDateConverter">
                <constructor-arg name="datePattern" value="yyyy-MM-dd"/>
            </bean>
        </set>
    </property>
</bean>
复制代码

之后,还需要给annotation-driven元素的conversion-service属性赋上bean名称,如下

<mvc:annotation-driven conversion-service="conversionService"/>

2Formatter
Formatter和Converter一样,也是将一种类型转换成另一种类型。但是,Formatter的源类型必须是一个String。
在使用时,必须编写一个实现org.springframework.format.Formatter接口的java类。这个接口的声明如下
复制代码
public interface Formatter<T> extends Printer<T>, Parser<T> { } public interface Printer<T> {     String print(T var1, Locale var2); } public interface Parser<T> {     T parse(String var1, Locale var2) throws ParseException; }
复制代码

这里的T表示输入字符串要转换的目标类型。
parse方法利用指定的Locale将一个String解析成目标类型。print方法相反,它是返回目标对象的字符串表示法。
下面展示了一个将String类型转换成Date类型的Formatter

复制代码
import org.springframework.format.Formatter;  import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale;  public class DateFormatter implements Formatter<Date>{     private String datePattern;     private SimpleDateFormat dateFormat;      public DateFormatter(String datePattern) {         this.dateFormat = dateFormat;         dateFormat = new SimpleDateFormat(datePattern);         dateFormat.setLenient(false);     }     public Date parse(String s, Locale locale) throws ParseException {         try {             SimpleDateFormat dateFormat = new SimpleDateFormat(datePattern);             dateFormat.setLenient(false);             return dateFormat.parse(s);         } catch (ParseException e) {             throw new IllegalArgumentException("invalid date format. Please use this pattern"" + datePattern + """);         }     }      public String print(Date date, Locale locale) {         return dateFormat.format(date);     } }
复制代码

为了使用Spring MVC应用程序定制的Formatter,需要在配置文件中添加一个conversionService bean。