Spring中配置方式

注解、xml配置方式

Posted by Reborn on October 31, 2018

Spring中常见注解

  • @Component:标注一个普通的Spring Bean类

  • @Respository:标注一个DAO的组件类

  • @Service:标注一个业务逻辑组件类

  • @Controller:标注一个控制器组件类

  • @Autowired:可用于为类的属性、构造器、方法进行注值

Spring技术:

  • 依赖注入(DI):控制反转(IOC)的一种具体实现

​ 注入方式有:通过构造函数传递参数的方式,通过使用setter方法的等等

  • 面向切面的编程(AOP):一个程序中跨越多个点的功能称为横切关注点 ,独立于业务逻辑,如日志记录、声明性事物、安全性以及缓存等等。

    AOP将横切关注点从他们所影响的对象中分离出来,DI则将应用程序彼此分离出来。

spring4.0

Spring Hello World实例:

首先定义一个HelloWorld类,有message属性以及相关的setter和getter方法,然后在MainApp文件中使用ClassPathXmlApplicationContext(“xxx.xml”)创建应用程序的上下文,创建初始化beans的配置文件所有的对象,之后可以通过getBean方法获取所需要的bean,根据bean的ID获取对象。在xml配置文件创建自己需要的实例化对象,从而不需要修改HelloWorld.java和MainApp.java文件。

Spring的BeanFactory容器:常用在移动设备和applet的应用中,最常用的XmlBeanFactory,通过xml加载初始化bean

Spring的ApplicationContext容器:

常用的:

  • FileSystemXmlApplicationContext:需要提供xml文件的绝对路径,该容器会从xml中加载已被定义的bean,

  • ClassPathXmlApplicationContext:在CLASSPATH环境变量中搜索XML配置文件,该容器就会从xml中加载配置文件,

  • WebXmlApplicationContext:在web应用程序的范围内加载xml配置文件

Bean:

​ bean是一个被实例化,组装,并且被Spring IOC容器所管理的对象。bean是由容器通过配置元数据创建的。

配置元数据对应bean定义的属性:

bean

Spring配置元数据:

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-3.0.xsd">

   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld" lazy-init="true" lazy-method="..." destroy-method="...">
       <property name="message" value="Hello World!"/>
   </bean>

</beans>

基于注解的配置方式:

  • @Require:应用于bean属性的setter方法。
  • @Autowired:应用于bean属性的setter方法和非setter方法,构造函数和属性。
  • @Qualifier:通过指定确切的将被连线的bean,通常和@Autowired一起使用来删除混乱。
  • JSR-250 Annotation

在IoC容器可以看到实例。

基于Java的配置方式:

以上两种方式都是需要配置xml的基础上编写spring bean,但是基于java config,可以在不用编写xml上完成spring bean的配置。

  • @Configuration:表明该类可以使用Spring IoC容器作为bean的定义来源
  • @Bean:将方法名作为bean的id
  • @Import(xxx.class):允许加载另外一个配置类@Bean定义
  • 生命周期回调:@Bean(initMethod=”xxx”, destoryMethod=”xxx”)
  • @Bean注解下可以使用@Scope注解指定Bean的范围

IoC容器

Bean的scope属性:

scope

<bean id="helloWorld" scope="singleton">
       <property name="message" value="Hello World!"/>
 </bean>

Bean的生命周期:

​ 初始化回调:类可以通过实现org.springframework.beans.factory.InitializingBean 的void afterPropertiesSet(),也可以通过XML的配置元数据中init-method指定一个void无参方法。

public class ExampleBean implements InitializingBean {
   @Overwrite	
   public void afterPropertiesSet() {
      // do some initialization work
   }
}
<bean id="exampleBean" 
         class="examples.ExampleBean" init-method="init"/>
         
//在类中定义一下方法
public class ExampleBean {
    public void init() {}
}

​ 销毁回调:通过可以通过实现org.springframework.beans.factory.DisposableBean的destory方法,亦或者在xml中配置destory-method属性

public class ExampleBean implements DisposableBean {
   @Overwrite
   public void destroy() {
      // do some destruction work
   }
}
<bean id="exampleBean"
         class="examples.ExampleBean" destroy-method="destroy"/>
         
public class ExampleBean {
   public void destroy() {
      // do some destruction work
   }
}

Spring的BeanPostProcessor:Bean的后置处理器

​ BeanPostProcessor接口定义了回调方法,可以通过这些方法实现自己的实例化逻辑,依赖解析等等,也可以对bean对象实例进行操作。

/*HelloWorld.java*/
public class HelloWorld {
   private String message;
   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
   public void init(){
      System.out.println("Bean is going through init.");
   }
   public void destroy(){
      System.out.println("Bean will destroy now.");
   }
}
/*InitHelloWorld.java*/
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;
public class InitHelloWorld implements BeanPostProcessor {
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("BeforeInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("AfterInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
}
/*MainApp.java*/
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      context.registerShutdownHook();//关闭hook,确保bean被销毁
   }
}

/*Beans.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-3.0.xsd">

   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld"
       init-method="init" destroy-method="destroy">
       <property name="message" value="Hello World!"/>
   </bean>

   <bean class="com.tutorialspoint.InitHelloWorld" order="..可以用来定义执行前后的顺序..."/>

</beans>

依赖注入(DI):

  • 构造器式注入:依赖性更强,传递参数可通过按顺序,传递参数属性亦或着索引。
public class TextEditor {
   private SpellChecker spellChecker;
   private String name;
   public TextEditor( SpellChecker spellChecker, String name ) {
      this.spellChecker = spellChecker;
      this.name = name;
   }
   public SpellChecker getSpellChecker() {
      return spellChecker;
   }
   public String getName() {
      return name;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}
<?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-3.0.xsd">

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor" 
      autowire="constructor">
      <constructor-arg value="Generic Text Editor"/>
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="SpellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>

</beans>
  • setter方式注入:可解耦合性更高
public class Foo {
   public Foo(Bar bar, Baz baz) {
      // ...
   }
}
<?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-3.0.xsd">

   <bean id="john-classic" class="com.example.Person">
      <property name="bar" ref="bar"/>
   </bean>

   <bean name="bar" class="com.example.Bar">
   </bean>

</beans>

注入内部Bean方式

<?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-3.0.xsd">

   <bean id="john-classic" class="com.example.Person">
       <property name="bar" ref="bar">
       		<bean name="bar" class="com.example.Bar"></bean>
       </property>
   </bean>
</beans>

集合类的注入有特定赋值方式,具体可见这个链接

以上的xml配置,均为显示注入依赖,Beans还可以通过指定bean的autowire属性为一个bean定义一个自动装配的模式:beans模式

@Required注解

import org.springframework.beans.factory.annotation.Required;
public class Student {
    private Integer age;
    
    @Required
    public void setAge(Integer age) {
        this.age = age;
    }
    public Integer getAge() {
        return age;
    }
}

对应的xml文件

<bean id="student" class="com.tutorialspoint.Student">
    <property name="name"  value="Zara" />

    <!-- try without passing age and check the result -->
    <!-- property name="age"  value="11"-->
</bean>

对应的property一定要写,否则会报以下错误

Property ‘age’ is required for bean ‘student’

@Autowired注解

  • 可以实现bean的autowired属性的功能
  • 可以去除setter方法,直接给需要注入的属性加上@Autowired注解即可
  • 可以用在构造器方法上
  • 默认此依赖是必须,可以通过@Autowired(required=false)关闭默认行为

@Qualifier(“”):指定具体对象注入

//Profile.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Profile {
   @Autowired
   @Qualifier("student1")//指定注入id为student1的bean
   private Student student;
   public Profile(){
      System.out.println("Inside Profile constructor." );
   }
   public void printAge() {
      System.out.println("Age : " + student.getAge() );
   }
   public void printName() {
      System.out.println("Name : " + student.getName() );
   }
}
//MainApp.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      Profile profile = (Profile) context.getBean("profile");
      profile.printAge();
      profile.printName();
   }
}
<!-- Definition for student1 bean -->
<bean id="student1" class="com.tutorialspoint.Student">
    <property name="name"  value="Zara" />
    <property name="age"  value="11"/>
</bean>

<!-- Definition for student2 bean -->
<bean id="student2" class="com.tutorialspoint.Student">
    <property name="name"  value="Nuha" />
    <property name="age"  value="2"/>
</bean>

输出结果:

Inside Profile constructor.
Age : 11
Name : Zara

Java Config方式配置示例

import org.springframework.context.annotation.*;
@Configuration
public class HelloWorldConfig {
   @Bean 
   public HelloWorld helloWorld(){
      return new HelloWorld();
   }
}

//以上代码等同于如下的xml配置
<beans>
   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld" />
</beans>
//mainApp.java
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.*;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext ctx = 
      new AnnotationConfigApplicationContext(HelloWorldConfig.class);
	 /*也可以通过如下方式加载多个配置文件
	  ApplicationContext ctx = new AnnotationConfigApplicationContext();
	  ctx.register(AppConfig.class, OtherConfig.class);
   	  ctx.register(AdditionalConfig.class);
   	  ctx.refresh();
	 */	
      HelloWorld helloWorld = ctx.getBean(HelloWorld.class);

      helloWorld.setMessage("Hello World!");
      helloWorld.getMessage();
   }
}

Spring框架的AOP

AOP:面向切面编程,横切关注点是指跨一个应用程序多个点的功能,例如日志记录、审计、安全性和缓存等等。

基于XML配置的实例

<aop:config>
   <aop:aspect id="myAspect" ref="aBean">
      <aop:pointcut id="businessService"
         expression="execution(* com.xyz.myapp.service.*.*(..))"/>
      <!-- a before advice definition -->
      <aop:before pointcut-ref="businessService" 
         method="doRequiredTask"/>
      <!-- an after advice definition -->
      <aop:after pointcut-ref="businessService" 
         method="doRequiredTask"/>
      <!-- an after-returning advice definition -->
      <!--The doRequiredTask method must have parameter named retVal -->
      <aop:after-returning pointcut-ref="businessService"
         returning="retVal"
         method="doRequiredTask"/>
      <!-- an after-throwing advice definition -->
      <!--The doRequiredTask method must have parameter named ex -->
      <aop:after-throwing pointcut-ref="businessService"
         throwing="ex"
         method="doRequiredTask"/>
      <!-- an around advice definition -->
      <aop:around pointcut-ref="businessService" 
         method="doRequiredTask"/>
   ...
   </aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>

使用@Aspect

在xml配置中只需要配置bean即可,以及在xml上加上«aop:aspectj-autoproxy/»配置

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
@Aspect
public class Logging2 {
    /** Following is the definition for a pointcut to select
     *  all the methods available. So advice will be called
     *  for all the methods.
     */
    @Pointcut("execution(* main.java.com.lqb.demo1.aop.*(..))")
    private void selectAll(){}
    /**
     * This is the method which I would like to execute
     * before a selected method execution.
     */
    @Before("selectAll()")
    public void beforeAdvice(){
        System.out.println("Going to setup student profile.");
    }
    /**
     * This is the method which I would like to execute
     * after a selected method execution.
     */
    @After("selectAll()")
    public void afterAdvice(){
        System.out.println("Student profile has been setup.");
    }
    /**
     * This is the method which I would like to execute
     * when any method returns.
     */
    @AfterReturning(pointcut = "selectAll()", returning="retVal")
    public void afterReturningAdvice(Object retVal){
        System.out.println("Returning:" + retVal.toString() );
    }
    /**
     * This is the method which I would like to execute
     * if there is an exception raised by any method.
     */
    @AfterThrowing(pointcut = "selectAll()", throwing = "ex")
    public void AfterThrowingAdvice(IllegalArgumentException ex){
        System.out.println("There has been an exception: " + ex.toString());
    }
}

Spring MVC

  • 模型封装了应用程序数据,它们一般有POJO组成
  • 视图用于呈现模型数据,一般由它生成客户端(浏览器)可以解析的HTML代码
  • 控制器用于处理用户请求,并返回合适的数据给视图

整体框架围绕DispatcherServlet设计,1554684539358

(此图来自w3cschool, 侵权即删)

简略流程:

  • 收到一个 HTTP 请求后,DispatcherServlet 根据 HandlerMapping 来选择并且调用适当的控制器
  • 控制器接受请求,并基于使用的 GET 或 POST 方法来调用适当的 service 方法。Service 方法将设置基于定义的业务逻辑的模型数据,并返回视图名称到 DispatcherServlet 中。
  • DispatcherServlet 会从 ViewResolver 获取帮助,为请求检取定义视图。
  • 一旦确定视图,DispatcherServlet 将把模型数据传递给视图,最后呈现在浏览器中。

spring mvc通过web.xml,配置url请求和处理