使用Spring简化JAVA开发

Spring的四种关键策略:

  ●基于POJO的轻量级和最小侵入式编程;

  ●通过依赖注入(DI)和面向接口实现松耦合;

  ●基于切面(AOP)和惯例进行声明式编程。

  ●通过切面和模板减少样板式代码。

几乎Spring所做的任何事都可以追溯到上面的一条或多条策略。

依赖注入(DI)

传统编程经常需要多个对象相互协作完成某个功能,每个对象管理与自己相互协作的对象。

传统开发常见的例子

比如下面的例子

一个Amercan类,其中有一个sayHello方法。

一个DoSomething类,调用American类执行sayHello方法。

public class  American{
public void sayHello(){
System.out.println("American say hello");
}
}
public class DoSomething{
private American american; //声明一个American类
DoSomething(){
this.american=new American(); //构造函数中初始化American类变量,这里与其紧耦合
}
public void do() {
person.sayHello();
}
}
public class Test {
public static void main(String[] args){
DoSomething doSomething=new DoSomething();
doSomething.sayHello();
}
}

可以发现在DoSomething类的构造函数自行创建了American类,与其紧密耦合在了一起,后期扩展、测试会面临很大困难。

改善后的例子:

public interface Person{
public void sayHello();
}
public class  American implements{
public void sayHello(){
System.out.println("American say hello");
}
}
public class DoSomething{
private Person person; //声明一个Person接口
DoSomething(Person person){
this.person=person; //person通过构造参数传入
}
public void do() {
person.sayHello();
}
}
public class Test {
public static void main(String[] args){
DoSomething doSomething=new DoSomething(new American); //在构造函数中传入Perison实现
doSomething.sayHello();
}
}

现在使声明一个Person接口,在DoSomething声明一个Person接口,将Person接口的实例通过构造器参数传入,没有与任何实现产生耦合,只要实现了Person接口的类都能sayHello。

使用Spring装配bean和注入

Spring有多中装配bean的方式,以下为2种常用的方式:

  ●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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
>
<bean id="doSomething" class="com.xyd.demo1.DoSomething">
<constructor-arg ref="person"/> <!-- 注入American -->
</bean> <bean id="person" class="com.xyd.demo1.American"><!-- American类 -->
</bean>
</beans>

以上xml声明了2个bean,一个DoSomething类,同时构造参数传入了American bean的引用。一个American类。

下面修改测试代码

    public static void main(String[] args) {
//DoSomething doSomething=new DoSomething(new American());
//doSomething.doing();
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("SayHello.xml");
DoSomething doSomething=context.getBean(DoSomething.class);
doSomething.doing();
}

使用XML应用上下文装载配置文件,然后使用getBean获得DoSomething类的实例,然后直接调用其doing()方法,输出American say hello!

四月 07, 2018 10:48:13 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@506c589e: startup date [Sat Apr 07 22:48:13 CST 2018]; root of context hierarchy
四月 07, 2018 10:48:13 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [SayHello.xml]
American say hello!

XML应用上下文获得了bean配置文件,得到DoSomething的引用后只需要简单的调用doing()就可以了,这个类完全不知道传入的是哪个Person接口的实例,只有配置文件中知道哪个实例被传入。

应用切面(AOP)

DI能然相互协作的软件保持松耦合,面向切面(AOP)允许把遍布应用各处的功能 分离出来形成可重用的组件。如需要在调用sayHello记录一下日志等等,通常称为横切关注点,借助AOP可以使这些服务模块化。

还是以上述例子,但是要增加一个功能,比如美国人说hello之前进行询问,之后给一个回应。

public class Reply {
public void sayHelloBefor(){ //sayHello前调用
System.out.println("say hello please!");
}
public void sayHelloAfter(){ //sayHello之后调用
System.out.println("really good");
}
}

传统的的做法是下面这样

public class DoSomething {
Person person;
Reply reply=new Reply();
public DoSomething(Person person){
this.person=person;
}
public void doing(){
reply.sayHelloBefor(); //DoSomething应该管理它吗?
person.sayHello();
reply.sayHelloAfter();
}
}

程序正常输出了

say hello please!
American say hello!
really good

但是这简单的代码变的复杂,如果还需要没有人进行回应的场景那会变得更复杂,而利用AOP可以声明在sayHello前必须进行请求和询问,而DoSomething本身不需要访问Reply的代码,下面修改配置文件。

<?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"
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.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
>
<bean id="doSomething" class="com.xyd.demo1.DoSomething">
<constructor-arg ref="person"/> <!-- 注入American -->
</bean> <bean id="person" class="com.xyd.demo1.American"> <!-- American类 -->
</bean> <bean id="reply" class="com.xyd.demo1.Reply"> <!-- Reply类 -->
</bean> <aop:config>
<aop:aspect ref="reply"> <!-- 引用reply bean -->
<aop:pointcut id="sayHello" expression="execution(* *.doing(..))" /> <!-- 定义切点( AspectJ切点表达式 )--> <aop:before method="sayHelloBefor" pointcut-ref="sayHello"/> <!-- 声明前置通知 --> <aop:after method="sayHelloAfter" pointcut-ref="sayHello"/> <!-- 声明后置通知 -->
</aop:aspect>
</aop:config>
</beans>

接下来运行一下程序,输出如下结果。

say hello please!
American say hello!
really good

AOP所做的事情,就是通过少量的配置,就可以吧Reply声明为一个切面,Reply仍然是一个POJO,不需要改变现有代码。

Bean容器

在Spring的应用中,应用对象生存于Spring容器中,容器负责创建、装配它们,配置并且管理对象的整个声明周期。容器是Spring框架的核心,使用DI管理构成应用的组件,会创建相互协作的组件之间的关联。

Spring中容器并不只有一个,其自带了多个容器实现,可归类为两种不同类型:

  ● bean工厂(由org.springframework.beans.factory.eanFactory接口定义,最简单,提供基本的DI支持)

  ● 应用上下文(由org.springframework.context.applicationContext接口定义,基于BeanFactory构建,提供应用框架级别的服务,例如从属性解析文本以及发布应用实践给感兴趣的事件监听者)

常用的容器类型为应用上下文,经常遇到的应用上下文:

  ● AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring上下文;

  ● AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载Spring Web的应用上下文

  ● ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。

  ● FileSystemXmlapplictioncontext:从文件系统下的一个或多个XML配置文件中加载上下文定义。

  ● XMLWebApplicationContext:从Web应用下的一个或多个XMl配置文件中加载上下文定义。

无论使用何种类型的应用上下文,将bean加载到bean工厂的过程都是相似的。

下面的代码加载一个xml配置文件的应用上下文:

ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("SayHello.xml");

获得应用上下文之后,就可以调用上下文的getBean()方法获得bean。

bean的生命周期

1、对bean进行实例化,new;

2、将值和bean的引用注入到bean对应的属性中 ;

3、如果bean实现了BeanNameAware接口,则将bean的ID传递给setBean-Name()方法;

4、如果bean实现了BeanFactoryAware接口,则调用setBeanFactory()方法,将BeanFactory容器实例传入;

5、如果bean实现了ApplicationContextAware接口,则将调用setApplicationContext()方法,将bean所在的应用上下文的引用传进来;

6、如果bean实现了BeanPostProcessor接口,则将调用它们的post-ProcessBeforeInitialization()方法;

7、如果bean实现了InitializeingBean接口,则将调用它们的after-PropertiesSet()方法,类似如果bean使用init-method声明了初始化方法,此方法也会调用。

8、如果bean实现了BeanPostProcessor,则将调用它们的post-ProcessAfterInitialization()方法;

9、此时bean已经准备就绪,可以被应用使用,它们将一直驻留在应用上下文中,直到上下文被销毁;

10、如果bean实现了DisposableBean接口,将调用它的destroy()接口方法,同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用;

随机推荐

  1. logback 常用配置详解&lt;appender&gt;

    logback 常用配置详解 <appender> <appender>: <appender>是<configuration>的子节点,是负责写日志的 ...

  2. EntityFramework 7 Linq Contains In 奇怪问题(已修复)

    问题说明: 博客问题纪录 Use EF7, Linq Contains In is error. EF7 Code Commit adding (client side) support for Co ...

  3. [MobilewebApp]图片的适配与清晰度

    iPhone4s的屏幕分辨率是640x960,这样就带来一个问题: 原来设计的320x480的设计出来的icon等图片,在高分辨率下就会显得模糊. 在经过讨论.查阅资料和测试后,可以有方法解决哦~ 1 ...

  4. [Call Vibrator] How to Enable Outgoing Call Vibration without ROOT

    Call Vibrator requires the radio log of phone to detect when outgoing call is answered. But since An ...

  5. asp.net mvc 事务处理:Transactions

    1.在控制器里引用using System.Transactions; 2.在你需要事务回滚的地方外面套一层using (TransactionScope sc = new TransactionSc ...

  6. .NET 配置文件实用指南

    我想大家对配置文件一定不会陌生,在大部分的项目中都会用到它,在此笔者给出一些配置文件的实用示例. XML配置文件 利用XML格式的配置文件储存连接字符串,再用反射技术读取. using System. ...

  7. 【PAT】B1009 说反话

    在输入时直接分别将每个单词放入字符串,逆序输出字符串数组 #include<stdio.h> int main(){ int num=0; char ans[90][90]; while( ...

  8. [Day12]构造方法、关键字this、super

    1.构造方法:对象创建时要执行的方法 (1)构造方法的格式: 修饰符 构造方法名(参数列表){} 体现: a.构造方法没有返回值类型,也不需要返回值 b.构造方法名称必须和类型保持一致 c.构造方法没 ...

  9. 编译openssl和Apache报错checking for SSL_CTX_new... no

    执行export LDFLAGS=-ldl命令后重新编译

  10. Java.WeakReference-SoftReference-PhantomReference

    Weak Reference, Soft Reference, Phantom Reference 1. Introduction "Weak reference objects, whic ...