Java 框架学习之 Spring

一. Spring 框架介绍。

Spring 框架是 一个基于 IoC 和 AOP 的 J2EE 框架。
IoC(控制反转,也叫作依赖注入) 是实现 Spring 的基础。IoC的作用是将控制权交给调用方,由调用方决定到底应该创建那个具体的实例。
IoC 在 Spring 框架中的作用是将以前程序员手动自己通过 new 创建对象交由 Spring 容器来进行。
AOP (面向切面编程) 即将需要实现的功能分为核心功能和周边功能,在 Spring AOP编程思想中,就将周边事物确定为切面。
核心功能和周边功能可以分开开发,最后整合编织在一起运行,就是 AOP。

二. Spring框架的依赖

首先需要 Spring 框架的 jar 包。
这里使用How2j 网站提供的整理好的 jar 包。点击下载
另外,推广一下这个网站,还是挺好用的。 How2j

三. Spring框架初探

Spring Ioc 部分

要想使用 Spring,首先我们需要对其进行配置。
在项目的根目录创建 applicationContext.xml 文件,并在其中添加一下内容。

<!-- applicationContext.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
   http://www.springframework.org/schema/context      
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
</beans>

创建我们需要的实体类Category,它有两个属性分别为 int 类型的 id 与 String 类型的 name,并分别实现他们的 getter 与 setter 方法。

// Category.java
public class Category {
    private int id;
    private String name;
    //getter,setter方法
}

然后修改我们的 appalicationContext.xml 文件。在 beans 标签内添加我们对应实体类的 bean 标签。添加方法如下:

<!-- applicationContext.xml -->

<?xml version="1.0" encoding="UTF-8"?>
<beans //...省略重复部分>

<bean name="category" class="com.tadecather.spring.pojo.Category">
    <property name="name" value="category 1" />
    <property name="id" value="12" />
</bean>

</beans>

其中 bean 标签内的 name 属性是 Spring 寻找实体类时所使用的名称,相当于时别名; class 属性 为对应实体类的完整名称,也就是 包名+类名。
bean 标签内的 <property> 标签内的 name 为对应的实体类的属性,value 标签为属性具体值。
可以每一个标签都配置属性,也可以选择一部分甚至全部都不设置属性,那么将采用对应类型的默认值为其赋值。

接下来编写我们的测试代码:

//TestSpring.java

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.tadecather.spring.pojo.Category;
import com.tadecather.spring.pojo.Product;
 
public class TestSpring {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext(
                new String[]{"applicationContext.xml"});
        Category c = (Category)context.getBean("category");
        System.out.println(c.getName() + ":" + c.getId());
        Product p = (Product) context.getBean("product");
        System.out.println(p.getId() + "name: " + p.getName());
    }
}

执行结果如下图所示:

如果 Product类中有一个 Category 类,那么我们应该要如何实现呐?
在 Product 类中添加属性Category category。 Category category; 并实现它的 getter,setter 方法。
修改 appalicationContext.xml 添加 另外一个 bean 标签。如下:

<!-- 
    <bean name="product" class="com.tadecather.spring.pojo.Product">
        <property name="id" value="13" />
        <property name="name" value="apple" />
        <property name="price" value="12.33" />
        <property name="category" ref="category" />
    </bean>

使用 ref 属性指向我们已经定义好的 category 的标签上。
修改TestSpring.java 的最后输出语句为 System.out.println(p.getCategory().getName());得到如下结果:

通过在上面的代码中使用 ref 属性,我们实现了注入对象的功能。
接下来,我们通过注解的方式实现对象注入:

  1. 在 applicationContext.xml 中添加这样一行:<context:annotation-config/>,同时删除上面 ref 的那一行。
  2. 在Product.java 的 category 属性前加上 @Autowired 注解。
  3. 然后运行我们的 TestSpring.java 得到如下结果:

    (是的,结果一样,原谅我用了一张图!)
  4. 在 setCategory() 前面添加 @AutoWired 达到同样的功能。
  5. 注解 @Resource(name="category") 也可以达到同样效果。

最后,我们来实现对 Bean 的注解。
删除 appalication 中的<bean> 子标签,以及刚刚添加的 <context:annotation-config/>
然后添加一行 <context:component-scan base-package="com.tadecather.spring.pojo"/>,告知我们的 Bean 组件在 这个包中。
最后,在Category 以及 Product 类的前面添加注释 @Component

运行我们的测试程序,结果如下:

Spring AOP 部分

使用标签实现

首先创建需要用到的核心业务类,里面只有一个方法 doSomeService(),用来简单的输出一句话。

// ProductService.java
public class ProductService {
    public void doSomeService(){
        System.out.println("do someService!");
    }
}

接下来,实现 Aspect 类,LoggerAspect 类,里面有一个 log() 方法,接受一个 ProceedingJoinPoint 参数,返回一个 Object 对象。

// LoggeAspect.java 
import org.aspectj.lang.ProceedingJoinPoint;
public class LoggerAspect {
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("start proceeding!" + joinPoint.getSignature().getName());
        Object object = joinPoint.proceed();
        System.out.println("end proceeding!" + joinPoint.getSignature().getName());
        return object;
    }
}

ProceedingJoinPoint 对象的 proceed() 会抛出一个 ThrowAble 。
最后修改 applicationContext.xml 如下:

<!-- applicationContext.xml 部分
<?xml version="1.0" encoding="UTF-8"?>
...

    <bean name="s" class="com.tadecather.spring.service.ProductService" />
    <bean id="loggerAspect" class="com.tadecather.spring.aspect.LoggerAspect"/>

    <aop:config>
        <aop:pointcut id="loggerCutpoint"
            expression=
            "execution(* com.tadecather.spring.service.ProductService.*(..)) "
        <aop:aspect id="logAspect" ref="loggerAspect">
            <aop:around pointcut-ref="loggerCutpoint" method="log"/>
        </aop:aspect>
    </aop:config>     
</beans>

在 xml 文件中,我们首先添加了 ProductService 与 LoggerAspect 的 Bean 标签。
然后,添加 <aop:config> 标签,在标签内对 AOP 进行配置。
需要配置的标签有两个,第一个为 <aop:pointcut> 这个标签指定程序在运行到哪一步时会触发下面一个标签 <aop:aspect> 的内容。
其中,expression 属性指明触发的条件 ,本例子中的触发条件为,当执行到 ProductService 类中的任何一个方法时,执行下面的切面函数。 第一个*指的是任意返回值,第二个*是任意函数函数,括号内的 .. 表示任意参数。

执行的步骤大致就是,执行到标记的函数的时候,会将程序的控制权交给切面函数,然后会在切面函数中执行需要执行的函数,当然,可以在执行之前添加一些别的操作,例如打印日志。

执行程序,效果如下:

使用注释实现

使用注释注入对象的方法修改 ProductService 类和 LoggerAspect 类。
然后在LoggeerAspect 类中加入实现 AOP的注释,修改后的 LoggerAspect 如下:

// LoggerAspect.java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component("loggerAspect")
public class LoggerAspect {
    @Around(value = "execution(* com.tadecather.spring.service.ProductService.*(..))")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("start proceeding!" + joinPoint.getSignature().getName());
        Object object = joinPoint.proceed();
        System.out.println("end proceeding!" + joinPoint.getSignature().getName());
        return object;
    }
}

@Aspect 直接表明这是一个切面
@Component("loggerAspect") 注解,表明这是一个别名为 loggerAspect 的 Bean 组件
@Around(value = "execution(* com.how2java.service.ProductService.*(..))") 表明在使用
com.tadecather.spring.service 的任意方法时,会触发这个切面处理函数。

并在 applicationContext.xml 文件中加入扫描路径,与自动处理 AOP 的语句。

<!-- applicationContext.xml 部分 -->
    <context:component-scan base-package="com.tadecather.spring.service"/>
    <context:component-scan base-package="com.tadecather.spring.aspect"/>
    <aop:aspectj-autoproxy/> 

执行 TestSpring.java 效果如下:


注解方式测试

要求:需要使用到测试依赖 jar 文件:junit-4.12.jar 和 hamcrest-all-1.3.jar ,下载并导入项目。
junit-4.12.jar
hamcrest-all-1.3.jar
操作:

  1. @RunWith(SpringJUnit4ClassRunner.class) 标注这是一个测试类
  2. @ContextConfiguration("classpath:applicationContext.xml") 配置文件位置
  3. @Test 测试方法
  4. 将 TestSpring 修改为下面形式
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("classpath:applicationContext.xml")
public class TestSpring {
    @Autowired
    Category c;
    @Test
    public void test(){
        System.out.println(c.getName());
    }
}
  1. 测试结果如下:

到此,Spring 框架的初步学习,到此结束。
以上内容 来自这里!
然后加上了一点我的学习思考。

2017.09.23 tadecather

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容