Spring是一个基于IOC和AOP的J2EE系统框架。
1.1、IOC/DI
IOC反转控制:是Spring的基础,Inversion Of Control 简单来说就是创建对象由以前的程序员自己new对象,构造方法来调用,变成了交由Spring创建对象。
DI依赖注入:Dependency Inject 简单来说就是拿到的对象的属性,已经被注入好了相关值,直接使用即可。
1.1.1、applicationContext.xml
在src目录下新建applicationContext.xml文件
applicationContext.xml是Spring的核心配置文件,通过关键字c即可获取Category对象,该对象获取的时候,即被注入了字符串“category 1”到name属性中
<?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">
<bean name="c" class="com.haxianhe.pojo.Category">
<property name="name" value="category 1" />
</bean>
</beans>
1.1.2、TestSpring
通过spring获取Category对象,以及该对象被注入的name属性。
package com.haxianhe.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.haxianhe.pojo.Category;
public class TestSpring {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "applicationContext.xml" });
Category c = (Category) context.getBean("c");
System.out.println(c.getName());
}
}
1.2、注入对象
在本例中,向Product对象中,注入Category对象
1.2.1、Product.java
package com.haxianhe.pojo;
public class Product {
private int id;
private String name;
private Category category;
...
以及每个属性对应的getter,setter方法
}
1.2.2、applicationContext.xml
在spring创建Product的时候注入一个Category对象
注意:这里要使用ref来注入另一个对象
<?xml version="1.0" encoding="UTF-8"?>
<beans ...">
<bean name="c" class="com.haxianhe.pojo.Category">
<property name="name" value="category 1" />
</bean>
<bean name="p" class="com.haxianhe.pojo.Product">
<property name="name" value="product1" />
<property name="category" ref="c" />
</bean>
</beans>
1.2.3、TestSpring
通过Spring拿到的Product对象已经被注入Cate对象了
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });
Product p = (Product) context.getBean("p");
System.out.println(p.getName());
System.out.println(p.getCategory().getName());
}
1.3、注解方式IOC/DI
本节内容是如何使用注解完成注入对象的效果
1.3.1、对依赖对象的注解
在xml文件中添加
<context:annotation-config/>
表示告诉Spring要用注解的方式进行配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="。。。">
<context:annotation-config/>
<bean name="c" class="com.haxianhe.pojo.Category">
<property name="name" value="category 1" />
</bean>
<bean name="p" class="com.haxianhe.pojo.Product">
<property name="name" value="product1" />
<!-- <property name="category" ref="c" /> -->
</bean>
</beans>
1.3.2、@Autowried
在Product.java的category属性前加上@Autowied注解
@Autowired
private Category category;
1.3.3、@Resource
除了@Autowired之外,@Resource也是常用的手段
@Resource(name="c")
private Category category;
1.3.4、对Bean的注解
修改applicationContext.xml,什么都去掉,只新增:
<context:component-scan base-package="com.haxianhe.pojo"/>
其作用是告诉Spring,bean都放在com.haxianhe.pojo这个包下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="...">
<context:component-scan base-package="com.how2java.pojo"/>
</beans>
1.3.5、@Component
为Product类加上@Component注解,即表明此类是bean
@Component("p")
public class Product {
另外,因为配置从applicationContext.xml中移出来了,所以属性初始化放在属性声明上进行了。
private String name="product 1";
private String name="category 1";
1.4、AOP
AOP即Asppect Oriented Propram面向切面编程:首先,在面向切面编程的思想里面,把功能分为核心业务功能和周边功能。
所谓核心业务,比如登录,增加数据,删除数据都叫核心业务
所谓周边功能,比如性能统计,日志,事务管理等等
周边功能在Spring的面向切面编程AOP思想里,即被定义为切面
在面向切面编程AOP的思想里,核心业务于功能和切面功能分别独立进行开发
然后把切面功能和核心业务功能“编织”在一起,这就叫AOP
1.4.1、准备业务类 ProductService
ProductService
package com.how2java.service;
public class ProductService {
public void doSomeService(){
System.out.println("doSomeService");
}
}
1.4.2、准备日志切面
该日志切面的功能是 在调用核心功能之前和之后分别打印日志,切面就是原理图中讲的那些辅助功能。
Object object = joinPoint.proceed();
就是将来与某个核心功能编织之后,用于执行核心功能的代码
package com.haxianhe.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
public class LoggerAspect {
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start log:" + joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
System.out.println("end log:" + joinPoint.getSignature().getName());
return object;
}
}
1.4.2、applicationContext.xml
<bean name="s" class="com.haxianhe.service.ProductService">
</bean>
生命业务对象
<bean id="loggerAspect" class="com.how2java.aspect.LoggerAspect"/>
生命日志切面
<aop:pointcut id="loggerCutpoint"
expression="execution(* com.haxianhe.service.ProductService.*(..)) "/>
指定右边的核心业务功能
<aop:aspect id="logAspect" ref="loggerAspect">
<aop:around pointcut-ref="loggerCutpoint" method="log"/>
</aop:aspect>
指定左边的辅助功能
然后通过aop:config把业务对象与辅助功能编织在一起
execution(* com.haxianhe.service.ProductService.*(..))
这表示对满足如下条件的方法调用,进行切面操作:
* 返回任意类型
com.haxianhe.service.ProductService.* 包名以com.haxianhe.service.ProductService开头的类的任意方法
(...)参数是任意数量和类型
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="。。。">
<bean name="s" class="com.how2java.service.ProductService">
</bean>
<bean id="loggerAspect" class="com.how2java.aspect.LoggerAspect"/>
<aop:config>
<aop:pointcut id="loggerCutpoint"
expression=
"execution(* com.how2java.service.ProductService.*(..)) "/>
<aop:aspect id="logAspect" ref="loggerAspect">
<aop:around pointcut-ref="loggerCutpoint" method="log"/>
</aop:aspect>
</aop:config>
</beans>
1.4.3、TestSpring
通过配置的方式,把切面和核心业务类编制在了一起。
运行测试,可以发现在编织之后,业务方法运行之前和之后分别会打印日志
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "applicationContext.xml" });
ProductService s = (ProductService) context.getBean("s");
s.doSomeService();
}
1.5、注解方式AOP
1.5.1、注解配置业务类
使用@Component("s")注解配置ProductService类
package com.haxianhe.service;
import org.springframework.stereotype.Component;
@Component("s")
public class ProductService {
public void doSomeService(){
System.out.println("doSomeService");
}
}
1.5.2、注解配置切面
@Aspect注解表示这是一个切面
@Component注解表示这是一个bean,由Spring进行管理
@Around(value="execution(* com.haxianhe.service.ProductService.*(..))")表示对com.haxianhe.service.ProductService这个类中的所有方法进行切面操作
package com.haxianhe.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggerAspect {
@Around(value = "execution(* com.how2java.service.ProductService.*(..))")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start log:" + joinPoint.getSignature().getName());
Object object = joinPoint.proceed();
System.out.println("end log:" + joinPoint.getSignature().getName());
return object;
}
}
1.5.3、applicationContext.xml
去掉原有信息,添加如下3行
<context:component-scan base-package="com.haxianhe.aspect"/>
<context:component-scan base-package="com.haxianhe.service"/>
扫描包com.haxianhe.aspect和com.haxianhe.service,定位业务类和切面类
<aop:aspectj-autoproxy/>
找到被注解了的切面类,进行切面配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="...">
<context:component-scan base-package="com.how2java.aspect"/>
<context:component-scan base-package="com.how2java.service"/>
<aop:aspectj-autoproxy/>
</beans>
1.6、注解方式测试
1.6.1、导入jar
注解测试方式用到了junit,所以需要导入junit-4.12.jar和hamcrest-all-1.3.jar
1.6.2、TestSpring
修改TestSpring, 并运行
1. @RunWith(SpringJUnit4ClassRunner.class)
表示这是一个Spring的测试类
2. @ContextConfiguration("classpath:applicationContext.xml")
定位Spring的配置文件
3. @Autowired
给这个测试类装配Category对象
4. @Test
测试逻辑,打印c对象的名称
package com.haxianhe.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.haxianhe.pojo.Category;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestSpring {
@Autowired
Category c;
@Test
public void test(){
System.out.println(c.getName());
}
}