Spring是一个基于IOC和AOP的结构J2EE系统的框架
IOC 反转控制 是Spring的基础,Inversion Of Control
简单说就是创建对象由以前的程序员自己new 构造方法来调用,变成了交由Spring创建对象
DI 依赖注入 Dependency Inject. 简单地说就是拿到的对象的属性,已经被注入好相关值了,直接使用即可。
必读: 基于框架的程序要成功运行,对于JAR包的版本,配置文件的正确性有着苛刻的要求,任何一个地方出错了,都会导致框架程序运行失败。 如果你是第一次学习本框架,务必严格按照教程的指导,完全模仿操作,直到成功看到运行效果。 第一次成功之后,信心,思路都会有较好的铺垫,然后再根据自己的疑惑,在“成功”的代码上做原本想做的改动和调整,这样可以大大节约学习的时间,提高效率,切勿一来就擅自改动,给自己的学习制造障碍
package vip.javer.pojo;
/** * @author Administrator */
public class Category {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<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">
<bean name="c" class="vip.javer.pojo.Category">
<property name="name" value="category 1"/>
bean>
beans>
测试代码,演示通过spring获取Category对象,以及该对象被注入的name属性。
到目前为止,简单的使用就是
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml")
得到的app对象getBean即可IOC就是交由Spring管理对象
DI就是依赖注入,简单说就是拿到对象属性
以获取对象的方式进行比较
传统方式
通过new关键字主动创建一个对象
IOC方式
对象的生命周期由Spring进行管理,直接去Spring那里获取一个对象,IOC是反转控制的缩写,就好比控制权原来在自己手里,现在转给了Spring
打个比喻:
<bean name="p" class="vip.javer.pojo.Product">
<property name="id" value="1"/>
<property name="name" value="产品1"/>
bean>
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
Product p = app.getBean("p",Product.class);
System.out.println(p.getId() + "\t" + p.getName());
在上例中,对Category的name属性注入了"category 1"字符串
在本例中 ,对Product对象,注入一个Category对象
<bean name="c" class="vip.javer.pojo.Category">
<property name="id" value="1"/>
<property name="name" value="分类1"/>
bean>
<bean name="p1" class="vip.javer.pojo.Product">
<property name="id" value="2"/>
<property name="name" value="产品2"/>
<property name="category" ref="c"/>
bean>
@Test
public void injectedObject() {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
Product p = app.getBean("p1", Product.class);
System.out.println(p);
}
在本知识点,会演示如何使用注解的方式完成注入对象中的效果
xml添加
表示告诉Spring要使用注解的方式进行配置
干掉之前的注入
,我的实际代码只是干掉了一行(随便哪行都行,方便后面进行注解完成该操作)
<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">
<context:annotation-config/>
<bean name="c" class="vip.javer.pojo.Category">
<property name="name" value="category 1"/>
<property name="id" value="233"/>
bean>
<bean name="p" class="vip.javer.pojo.Product">
<property name="id" value="1"/>
<property name="name" value="产品"/>
bean>
<bean name="p1" class="vip.javer.pojo.Product">
<property name="id" value="2"/>
<property name="name" value="产品2"/>
bean>
beans>
在Product的category属性前加上注解@Autowired
package vip.javer.pojo;
import org.springframework.beans.factory.annotation.Autowired;
/** * @author Administrator */
public class Product {
int id;
String name;
@Autowired
Category category;
@Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
", category=" + category +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
}
测试
@Test
public void injectedObject() {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
Product p = app.getBean("p1", Product.class);
System.out.println(p);
}
除了在属性前加上@Autowired,还可以在setCategory方法前加上@Autowired,是相同的效果
@Resource(name = "c")
Category category;
上述例子是对注入对象行为的注解,那么bean对象本身,比如Category,Product可不可以移出applicationContext.xml配置文件,也通过注解进行呢?
接下来就讲解如何对Bean进行注解配置
修改applicationContext.xml,什么都去掉,只新增一行代码
<context:component-scan base-package="vip.javer.pojo"/>
该代码的作用是告诉Spring,bean都放在了vip.javer.pojo这个包下
运行可以看到和之前的效果一样,之前的p1由于@Component声明的p,自然失败了
AOP 即 Aspect Oriented Program 面向切面编程
首先,在面向切面编程的思想里面,把功能分为核心业务功能 ,和周边功能。
所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
所谓的周边功能,比如性能统计,日志,事务管理等等
周边功能在Spring的面向切面编程AOP思想里,即被定义为切面
在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发
然后把切面功能和核心业务功能 “编织” 在一起,这就叫AOP
例如现在我也业务核心代码是sout,我想对核心代码切入日志功能
准备业务类
package vip.javer.service;
/** * @author Administrator */
public class ProductService {
public void doSomeService() {
System.out.println("doSomeService");
}
}
准备日志切面LoggerAspect
package vip.javer.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
/** * @author Administrator */
public class LoggerAspect {
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start log:\t" + joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
System.out.println("eng log:\t" + joinPoint.getSignature().getName());
return object;
}
}
需要解释一下的是,该日志切面的功能是在调用核心功能之前和之后分别打印日志
Object object = joinPoint.proceed();
就是将来与某个核心功能编制之后,用于执行核心功能的代码
applicationContext.xml配置
<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">
<bean name="s" class="vip.javer.service.ProductService"/>
<bean id="log" class="vip.javer.aspect.LoggerAspect"/>
<aop:config>
<aop:pointcut id="loggerCutpoint" expression="execution(* vip.javer.service.ProductService.*(..))"/>
<aop:aspect id="logAspect" ref="log">
<aop:around method="log" pointcut-ref="loggerCutpoint"/>
aop:aspect>
aop:config>
beans>
按照注释的顺序查看
解释一下execution(* vip.javer.service.ProductService.*(..))
,这表示对满足如下条件的方法调用,进行切面操作
*
返回任意类型
vip.javer.service.ProductService.*
以vip.javer.service.ProductService
开头的类的任意方法
(..)
参数是任意数量和类型
测试
TestSpring 代码没有发生任何变化,通过配置的方式,把切面和核心业务类编制在了一起。
运行测试,可以发现在编织之后,业务方法运行之前和之后分别会打印日志
参考上述的日志切面,做一个性能统计切面,并编织在业务方法上面。
注: 在业务方法方法中,做一些JDBC访问,以增加耗时
由于已有主业务类ProductService,故略过
性能统计切面PerformanceStatisticsAspect
package vip.javer.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
/** * @author Administrator */
public class PerformanceStatisticsAspect {
public Object statistics(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object object = joinPoint.proceed();
Thread.sleep(500);
long endTime = System.currentTimeMillis();
long runningTime = endTime - startTime;
System.out.println("运行时间:\t[" + runningTime + "ms]");
return object;
}
}
配置applicationContext.xml
<bean name="per" class="vip.javer.aspect.PerformanceStatisticsAspect"/>
<aop:config>
<aop:pointcut id="ps" expression="execution(* vip.javer.service.ProductService.*(..))"/>
<aop:aspect id="statistics" ref="per">
<aop:around method="statistics" pointcut-ref="ps"/>
aop:aspect>
aop:config>
测试
@Test
public void aopCutIntoTheAnswer() {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
ProductService s = app.getBean("s", ProductService.class);
s.doSomeService();
}
aop:config
配置的一些说明注解很简单,基于上面的例子
)不同切面类可通过实现org.springframework.core.Ordered 接口实现切面类的优先级控制,具体为重写getOrder方法,定制返回值,返回值(int 类型)越小优先级越大
例如我想让性能监控最先
package vip.javer.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
/** * @author Administrator */
@Aspect
@Component
public class PerformanceStatisticsAspect implements Ordered {
@Around("execution(* vip.javer.service.ProductService.*(..))")
public Object statistics(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("测试内容");
long startTime = System.currentTimeMillis();
Object object = joinPoint.proceed();
Thread.sleep(500);
long endTime = System.currentTimeMillis();
long runningTime = endTime - startTime;
System.out.println("运行时间:\t[" + runningTime + "ms]");
return object;
}
@Override
public int getOrder() {
return 1;
}
}
注解方式用到了junit,所以需要下载:
junit-4.12.jar和hamcrest-all-1.3.jar
导包
修改TestSpring
修改TestSpring, 并运行
@RunWith(SpringJUnit4ClassRunner.class)
表示这是一个Spring的测试类
@ContextConfiguration(“classpath:applicationContext.xml”)
定位Spring的配置文件
@Autowired
给这个测试类装配Category对象
@Test
测试逻辑,打印c对象的名称
package vip.javer.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import vip.javer.pojo.Category;
import vip.javer.pojo.Product;
import vip.javer.service.ProductService;
/** * @author Administrator */
/*1. 表明这是Spring的测试类*/
@RunWith(SpringJUnit4ClassRunner.class)
/*2. 定位Spring的配置文件*/
@ContextConfiguration("classpath:applicationContext.xml")
public class TestSpring {
/*3. 给测试类装配Category对象*/
@Autowired
private Category c;
/*4. 测试逻辑,打印c的名称*/
@Test
public void annotationTest() {
System.out.println(c.getName());
}
@Test
public void gettingObjectsUsingSpring() {
// ApplicationContext app = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
Category c = (Category) app.getBean("c");
System.out.println(c.getId() + "\t" + c.getName());
Product p = app.getBean("p", Product.class);
System.out.println(p.getId() + "\t" + p.getName());
}
@Test
public void annotationMode() {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
Product p = app.getBean("p", Product.class);
System.out.println(p);
}
@Test
public void aopTest() {
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
ProductService ps = app.getBean("s", ProductService.class);
ps.doSomeService();
}
}