目前java主流的开源框架无论是ssh还是ssi,除了spring,其他的框架都有可替换的框架struts2和springmvc,hibernate和ibatis(mybatis),这里我们不讨论其他的框架的优劣。那为什么spring这么受开发者的欢迎呢?那就是spring的优点,博主以为spring的优点有:
1.轻量级:你可以选择你想要的服务,还有代码的低侵入性。
2.控制反转ioc:Spring使用控制反转技术实现了松耦合。依赖被注入到对象,而不是创建或寻找依赖对象。
3.面向切面编程aop:Spring支持面向切面编程,同时把应用的业务逻辑与系统的服务分离开来。
4.事务管理:spring有着强大的事务处理能力。
5.集成性:能很好的集成其他的框架。
那下面我们结合着代码依次来说说spring的各个有点
4.0.0
com.julyday
myspring
0.0.1-SNAPSHOT
jar
myspring
http://maven.apache.org
UTF-8
4.1.4.RELEASE
junit
junit
4.12
test
org.springframework
spring-core
org.springframework
spring-beans
org.springframework
spring-context
org.springframework
spring-framework-bom
${spring.version}
pom
import
上面是我们需要用到的spring的模块,就三个,我们再看看jar包,包括junit4一共才9个jar包,是不是很优雅。
public interface Person {
public void eat();
}
接着是作者本人这个类:
public class Author implements Person {
@Override
public void eat() {
System.out.println("作者喜欢吃肉");
}
}
建一个spring-bean.xml,如下:
测试下:
package com.julyday.myspring;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
@RunWith(BlockJUnit4ClassRunner.class)
public class BeanTest extends BaseTest{
@Test
public void testBean(){
Person author = (Person)context.getBean("author");
author.eat();
}
}
package com.julyday.myspring;
import org.junit.After;
import org.junit.Before;
import org.springframework.beans.BeansException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BaseTest {
public ClassPathXmlApplicationContext context;
@Before
public void before() {
try {
context = new ClassPathXmlApplicationContext("spring-bean.xml");
context.start();
} catch (BeansException e) {
e.printStackTrace();
}
}
@After
public void after() {
context.destroy();
}
}
选中testBean方法右键运行Junit Test,运行成功。
public class American implements Person{
@Override
public void eat() {
System.out.println("美国人喜欢吃牛肉");
}
}
@RunWith(BlockJUnit4ClassRunner.class)
public class ScopeTest extends BaseTest{
@Test
public void testBean(){
Person p1 = (Person)context.getBean("author");
p1.eat();
Person p2 = (Person)context.getBean("author");
p2.eat();
System.out.println(p1.hashCode());
System.out.println(p2.hashCode());
Person p3 = (Person)context.getBean("american");
p3.eat();
Person p4 = (Person)context.getBean("american");
p4.eat();
System.out.println(p3.hashCode());
System.out.println(p4.hashCode());
}
}
从运行的结果可以看出来,作者只此一家别无分店,而作者的美国朋友有很多个。
public class Zhangsan implements Person {
public void init(){
System.out.println("Zhangsan带礼物去看朋友");
}
@Override
public void eat() {
System.out.println("Zhangsan吃了一碗饭");
}
public void destroy(){
System.out.println("Zhangsan聊的很开心");
}
}
public class Lisi implements Person {
public void init(){
System.out.println("Lisi带礼物去看朋友");
}
@Override
public void eat() {
System.out.println("Lisi喝了二两白酒");
}
public void destroy(){
System.out.println("Lisi喝多了");
}
}
public class LazyTest extends BaseTest {
@Test
public void testBean(){
// Zhangsan zhangsan = (Zhangsan)context.getBean("zhangsan");
// zhangsan.eat();
Lisi lisi = (Lisi)context.getBean("lisi");
lisi.eat();
}
}
张三一开始没来,我们运行下,看到好像spring让张三来了,不科学啊!但仔细一看张三没eat 啊,这里就要讲下spring管理bean的加载机制了,默认的是在容器启动的时候spring把所有的
单例的bean都创建出来的,张三单例,所以spring就调用了他的初始化方法init,当容器关闭的时候又调用了他的destroy方法。
其他的类加入注解如下:(为了便于比较,我们新建了一个包com.julyday.myspring.annotation)
@Component
@Scope("prototype")
public class American implements Person{
@Override
public void eat() {
System.out.println("美国人喜欢吃牛肉");
}
}
@Component
public class Author implements Person{
@Override
public void eat() {
System.out.println("作者喜欢吃肉");
}
}
@Component
public class Lisi implements Person{
@PostConstruct
public void init(){
System.out.println("Lisi带礼物去看朋友");
}
@Override
public void eat() {
System.out.println("Lisi喝了二两白酒");
}
@PreDestroy
public void destroy(){
System.out.println("Lisi喝多了");
}
}
@Lazy(false)
@Component
public class Zhangsan implements Person{
@PostConstruct
public void init(){
System.out.println("Zhangsan带礼物去看朋友");
}
@Override
public void eat() {
System.out.println("Zhangsan吃了一碗饭");
}
@PreDestroy
public void destroy(){
System.out.println("Zhangsan聊的很开心");
}
}
好的,我们再把BaseTest.java里面的before方法context初始化修改成:context = new ClassPathXmlApplicationContext("spring-beanannotation.xml");
package com.julyday.myspring.aop;
public interface Person {
public void back(String destination);
}
一样的博主
public class Author implements Person{
@Override
public void back(String destination) {
System.out.println("作者准备"+destination);
}
}
public class BeforeAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("各位朋友再见!");
String argString = "";
if(args.length > 0){
for(Object obj : args){
argString += obj.toString();
}
}
System.out.println("BeforeAdvice before : method : "+method.getName()
+" args : "+argString+" target : "+target.getClass().getName());
}
}
com.julyday.myspring.aop.Person
beforeAdvice
新建一个测试类
@RunWith(BlockJUnit4ClassRunner.class)
public class ApiTest extends BaseTest{
@Test
public void testApi(){
Person p = (Person)context.getBean("author");
p.back("回家");
}
}
public class BaseTest {
public ClassPathXmlApplicationContext context;
@Before
public void before() {
try {
context = new ClassPathXmlApplicationContext("spring-aop-api.xml");
context.start();
} catch (BeansException e) {
e.printStackTrace();
}
}
@After
public void after() {
context.destroy();
}
}
在博主回家前,spring完成了博主礼貌的before方法。
public class AroundAdvice implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("小红让博主去如家666房间斗地主");
Object obj = invocation.proceed();
System.out.println("博主告诉小红,晚上有事明天再约");
return obj;
}
}
当博主准备去打牌的时候,老婆打电话让我回家陪她看电影:
public class Author implements Person{
@Override
public void back(String destination) {
System.out.println("作者准备"+destination);
throw new RuntimeException("老婆打电话让我回家陪她看电影");
}
}
public class ThrowExAdvice implements ThrowsAdvice{
public void afterThrowing(Exception ex) throws Throwable {
System.out.println("ThrowExAdvice afterThrowing 1"+ex.getMessage());
}
public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {
System.out.println("ThrowExAdvice afterThrowing 2 : " + ex.getMessage());
}
}
public class AfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("博主结束快乐的一天的行程");
}
}
总的spring-aop-api.xml修改如下:
@RunWith(BlockJUnit4ClassRunner.class)
public class ApiTest extends BaseTest{
@Test
public void testApi(){
Person p = (Person)context.getBean("author");
p.back("去打牌");
}
}
这里需要注意的是,当程序走到了ThrowExAdvice后,afterAdvice是不会执行的,如果没有异常的话,afterAdvice是会执行的。
org.springframework
spring-aspects
新增一个切面类AuthorAspect,切面类里面有各种不通方法:
package com.julyday.myspring.aop.schema;
import org.aspectj.lang.ProceedingJoinPoint;
public class AuthorAspect {
public void before() {
System.out.println("AuthorAspect before.");
}
public void afterReturning() {
System.out.println("AuthorAspect afterReturning.");
}
public void afterThrowing() {
System.out.println("AuthorAspect afterThrowing.");
}
public void after() {
System.out.println("AuthorAspect after.");
}
public Object around(ProceedingJoinPoint pjp) {
Object obj = null;
try {
System.out.println("AuthorAspect around 1.");
obj = pjp.proceed();
System.out.println("AuthorAspect around 2.");
} catch (Throwable e) {
e.printStackTrace();
}
return obj;
}
}
新增spring-aop-schema-advice.xml文件:
两个bean不多说了,在config里面先定义一个切面,指向切面的bean,切面里面定义一个切点pointcut,切点是告诉spring你从那个地方去切入,后面就是要切入的时机了。
package com.julyday.myspring.aop.schema;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import com.julyday.myspring.aop.Person;
@RunWith(BlockJUnit4ClassRunner.class)
public class SchemaTest extends BaseTest{
@Test
public void testApi(){
Person p = (Person)context.getBean("author");
p.back("去打牌");
}
}
package com.julyday.myspring.aop.schema;
import org.junit.After;
import org.junit.Before;
import org.springframework.beans.BeansException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BaseTest {
public ClassPathXmlApplicationContext context;
@Before
public void before() {
try {
context = new ClassPathXmlApplicationContext("spring-aop-schema-advice.xml");
context.start();
} catch (BeansException e) {
e.printStackTrace();
}
}
@After
public void after() {
context.destroy();
}
}
这里需要指出的是如果出现异常,后面的after 和afterReturning是会继续执行的,和api的有点不一样。
package com.julyday.myspring.aop.aspectj;
import org.springframework.stereotype.Component;
import com.julyday.myspring.aop.Person;
@Component
public class Author implements Person {
@Override
public void back(String destination) {
System.out.println("作者准备"+destination);
throw new RuntimeException("老婆打电话让我回家陪她看电影");
}
}
package com.julyday.myspring.aop.aspectj;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AuthorAspect {
@Pointcut("execution(* com.julyday.myspring.aop.aspectj.Author.*(..))")
public void pointcut(){}
@Before("execution(* com.julyday.myspring.aop.aspectj.Author.*(..))")
public void before() {
System.out.println("AuthorAspect before.");
}
@AfterReturning(value="pointcut()")
public void afterReturning() {
System.out.println("AuthorAspect afterReturning.");
}
@AfterThrowing("pointcut()")
public void afterThrowing() {
System.out.println("AuthorAspect afterThrowing.");
}
@After("pointcut()")
public void after() {
System.out.println("AuthorAspect after.");
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint pjp) {
Object obj = null;
try {
System.out.println("AuthorAspect around 1.");
obj = pjp.proceed();
System.out.println("AuthorAspect around 2.");
} catch (Throwable e) {
e.printStackTrace();
}
return obj;
}
}
spring-aop-aspectj.xml:
测试下:
package com.julyday.myspring.aop.aspectj;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import com.julyday.myspring.aop.Person;
@RunWith(BlockJUnit4ClassRunner.class)
public class AspectjTest extends BaseTest{
@Test
public void aspectjApi(){
Person p = (Person)context.getBean("author");
p.back("去打牌");
}
}
package com.julyday.myspring.aop.aspectj;
import org.junit.After;
import org.junit.Before;
import org.springframework.beans.BeansException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BaseTest {
public ClassPathXmlApplicationContext context;
@Before
public void before() {
try {
context = new ClassPathXmlApplicationContext("spring-aop-aspectj.xml");
context.start();
} catch (BeansException e) {
e.printStackTrace();
}
}
@After
public void after() {
context.destroy();
}
}
这种方式和xml配置的方式基本差不多。