Spring是一个开源框架,其主要优势就是其是分层框架,可以让开发者自由使用哪些组件。
Spring主要由7个模块组成,每个模块都可以单独存在,也可以多个模块共同使用。
我们先不说模块,我们先说Spring的两个主要概念:
1.控制反转:顾名思义,控制某个对象的权利从自己手中移到了Spring手中。
比如:原本在程序的主函数中我需要一个猫对象,老鼠对象,狮子对象等等,那么我就需要手动new一个猫对象,老鼠对象,狮子对象等等。。.
而使用了Spring之后,现在我不需要手动new一个对象,我只需要将这些猫对象,老鼠对象,狮子对象等等这些类的的位置告诉Spring,让他去管理,当我想要获取这些对象的时候我告诉Spring一下,我需要这些对象,你给我new一个,spring就能给我new一个,完全省去不必要的繁琐代码等等。
未使用Spring前的代码:
创建主函数:
package com.strategy.jpa; public class animal { public static void main(String[] args) { Cat cat=new Cat(); cat.setAge(1); cat.setName("猫咪"); Mouse mouse=new Mouse(); mouse.setAge(2); mouse.setName("米老鼠"); } }
创建两个动物类Cat和Mouse:
package com.strategy.jpa; public class Cat { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
package com.strategy.jpa; public class Mouse { private String name; private int age; public Mouse() { } public Mouse(String name,int age) { this.name=name; this.age=age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void Cry() { System.out.println("叽叽"); } }使用Spring后的代码: 首先添加Spring.jar包(这个就不再多说了)
创建beans.xml,用来配置相关的bean.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="cat" class="com.strategy.jpa.Cat"> <property name="name" value="喵咪"/> <property name="age" value="1"/> </bean> <bean id="mouse" class="com.strategy.jpa.Mouse"> <property name="name" value="米老鼠"/> <property name="age" value="2"/> </bean> </beans>在主函数添加下列语句:
package com.strategy.jpa; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class animal { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");//读取beans.xml中的内容 Cat p = ctx.getBean("cat",Cat.class);//创建bean的引用对象 p.Cry(); } }有的人会疑惑,方便到那里了啊?
仔细想一下会发现,如果主函数需要多种动物类呢?
比如说,主函数还需要老虎类,狮子类,企鹅类对象等等,一个一个手动new确实很烦麻,通过xml的配置却方便一些。
在上面的代码中,我们只需要创建一个ApplicationContext,让其读取xml,然后根据我们的需要让Spring返给我们所需要的对象即可,具体方便在哪里呢?
当主函数不需要某个动物,或者说是需要同种动物的不同信息的时候(例如:原本需要小猫咪,现在需要大猫咪),只需要让spring创建一个另外的bean就行,不像之前的方法需要修改主函数中的代码就能达到同样的目的,还有不同对象之间联系也能因此而解耦合。
这里说的不是很清楚,大家可以看一下大话设计模式这本书,这本书对对象的解耦,以及工厂模式讲得非常清楚。
上述的代码中,我想说的是,Spring的控制反转利用反射和Key-Value(键值对),将配置文件的属性注入到对象中,做到随时获取,随时有值,随时可用的目的。
因为是键值对,所以beans.xml中bean的id必须是唯一的。
上述的方式是通过set方式将xml中的属性注入到cat对象中的。
还有一种方式也能注入,它是:构造函数注入。
构造函数注入和set注入类似,只是多写了几句话来说明注入的参数要往构造函数的参数注入。代码如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="cat" class="com.strategy.jpa.Cat"> <property name="name" value="喵咪"/> <property name="age" value="1"/> </bean> <bean id="mouse" class="com.strategy.jpa.Mouse"> <property name="name" value="米老鼠"/> <property name="age" value="2"/> </bean> <bean id="mouse1" class="com.strategy.jpa.Mouse"> <constructor-arg value="米老鼠" /> <constructor-arg value="222" /> </bean> </beans>
还有一种是接口注入:spring不用这种方式,因为接口注入说到底也就是set注入,spring也就没用这种方式。
再说一下代码中的ApplicationContext,ApplicationContext是一个接口,他是BeanFactory的子接口。
ApplicationContext和BeanFactory都可以认为是spring中管理Bean的容器,因为调用时是通过接口去调用这两个接口的实现类的。
因为实现该接口的实现类是容器,所以可以通过接口去管理容器Beans,我们通常用ApplicationContext去管理beans.
这里要说一下实现类:ApplictionContext的实现类为FileSystemXmlApplicationContext和ClassPathXmlApplicationContext
FileSystemXmlApplicationContext:基于文件系统的XML配置文件创建ApplicationContext;
ClassPathXmlApplicationContext:基于类加载路径下的xml配置文件创建ApplicationContext。
看不懂无所谓,你只要知道上面两个实现类的作用是,通过不同的寻找方式,找到xml然后创建ApplicationContext。
其实,Spring加载beans.xml文件时,给beans中的bean写数据都是有一个流程的,这个流程和JavaWeb中的Listener很相似,不再过多阐述。
想要了解的可以看下面的链接:http://blog.csdn.net/u011704894/article/details/44407145
看不懂的可以看我的一篇文章:http://blog.csdn.net/u012605477/article/details/75308241
注意:ApplicationContext和application(ServletContext)是两码事,前者针对Spring而言,后者针对JSP而言。
2.面向切面:就是将一些方法或者其他操作当成一个切面。
比如:拿支付宝取钱举例,每当我们向朋友转账,查询自己余额,修改密码等操作时。我们都需要进行一个操作,那就是登录验证,在以往的编码中,登录验证分别放到每个模块中。
比如说,向朋友转账模块里有个登录验证,查询自己余额有个登录验证,现在我们把这个登录验证提取出来,让三者都能使用,进行相关操作时都能使用该验证,这个时候这个验证就叫做切面。
从代码的层面讲:就是编写一个切面类,然后在xml中将这个切面类交给aop框架管理,然后再在xml中声明一个切点(这个切点就是上面例子所说的登录验证方法),然后再在xml文件中的【切点前后】执行一下【切面类的相关方法】,供其对切点进行处理。
下面为代码:
切点类:
package com.strategy.jpa; import org.springframework.stereotype.Repository; //切点类方法 public class SpringAopDemo { public void show(){ System.out.println("执行了切点的show方法"); } }切面类:
package com.strategy.jpa; import org.aspectj.lang.ProceedingJoinPoint; //切面类 public class SpringAop { public void beforeShow(){ System.out.println("执行aop切点方法前"); } public void afterShow(){ System.out.println("执行aop切点方法后"); } /* 这里引用了Aop框架*/ public void around(ProceedingJoinPoint joinpoint){ System.out.println("开始执行aop切点方法"); long start = System.currentTimeMillis(); try { joinpoint.proceed(); } catch (Throwable e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("执行aop切点方法用时: "+(end-start)+" ms"); } }
beans.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-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd" default-lazy-init="true"> <!--spring可以自动去扫描base-pack下面或者子包下面的Java文件,如果扫描到有@Component @Controller@Service@Repository等这些注解的类,则把这些类注册为bean --> <!-- 名称不一样是因为这样可以对不同功能的bean进行分类 --> <!-- 这里将SpringAopDemo纳入了Spring管理 --> <context:component-scan base-package="com.strategy.jpa" /> <bean id="springAopDemo" class="com.strategy.jpa.SpringAopDemo" /> <!-- 将我们的切面类声明为一个bean --> <bean id="springAop" class="com.strategy.jpa.SpringAop" /> <!-- 进行切面配置 --> <aop:config> <!-- 将切面类注入到aop框架中 --> <aop:aspect ref="springAop"> <!-- 声明一个切点,切点的意思是,哪些方法需要被执行aop,这里指定SpringAopDemo.show(..)需要执行aop方法,并对需要执行AOP的方法设定id --> <aop:pointcut expression="execution(* com.strategy.jpa.SpringAopDemo.show(..))" id="performance" /> <!-- 下面的before就是在标注的方法id前后,执行相关操作。 --> <aop:before method="beforeShow" pointcut-ref="performance" /> <aop:after method="afterShow" pointcut-ref="performance" /> <aop:around method="around" pointcut-ref="performance" /> </aop:aspect> </aop:config> </beans>主函数的调用:
package com.strategy.jpa; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class animal { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");//读取bean.xml中的内容 SpringAopDemo aopDemo=ctx.getBean("springAopDemo",SpringAopDemo.class); aopDemo.show(); } }
运行结果
是否和Servlet的创建销毁过程类似呢?
只不过Servlet的创建有init方法进行初始化,执行有Service方法操作,销毁有destory方法。
而aop这里变成了切面的方式,即通过xml配置的方式,根据自己抉择是否需要init方法和destory方法。
名称不同,方法的功能不同,但调用的顺序类同,操作异曲同工。
至此,应该大概明白了AOP能做什么了,如果你想了解更多,请看下面这位大神的博客。
http://blog.csdn.net/yunshixin/article/details/52444049
以上对Spring的bean配置都是通过xml进行配置的,对于新上手者看起来很直观,但是写的代码多了xml就很繁琐了,所以要换一种配置方式,即
Spring的注解使用方式:
1.在benas.xml中配置spring要管理的bean,即指定包下的bean(注解类)归于spring管理.
<?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-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd" default-lazy-init="true"> <!--spring可以自动去扫描base-pack下面或者子包下面的Java文件,如果扫描到有@Component @Controller@Service@@Repository等这些注解的类,则把这些类注册为bean --> <!-- 名称不一样是因为这样可以对不同功能的bean进行分类 --> <!-- 这里将SpringAopDemo纳入了Spring管理 --> <context:component-scan base-package="com.spring.demo2" /> </beans>
主函数代码:
package com.spring.demo2; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class animal { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");// 读取bean.xml中的内容 Cat cat = (Cat) ctx.getBean("cat"); cat.Cry(); Mouse mouse = (Mouse) ctx.getBean("mouse"); mouse.Cry(); } }实体类Cat和Mouse代码:
package com.spring.demo2; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Repository; @Repository public class Cat { @Value("我的名字叫猫咪") private String name; private int age; public void Cry() { System.out.println(this.name); System.out.println("喵喵"); } } package com.spring.demo2; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Repository; @Repository public class Mouse { @Value("我的名字叫老鼠") private String name; private int age; public void Cry() { System.out.println(this.name); System.out.println("叽叽"); } }运行结果:
原本需要在bean.xml中的配置bean,现在不需要了,原本需要在xml中配置bean的属性,现在也不需要了。
由此可知,spring的注解配置十分的方便,只需要在指定的类上加上注解即可。
注意:加上注解的bean类,通过获取其ApplicationContext获取的时候,一定要将该类的名称首字母小写,这是spring定义的。
不然获取不到,会产生以下错误。
spring的基本用法讲完了,但是Spring注解的分类与区别还未叙述,这点东西太多了,有点说不完,建个参考下面大神的博客,写的也挺详细。
http://blog.csdn.net/xyh820/article/details/7303330/