[关闭]
@snail-lb 2016-07-22T13:36:51.000000Z 字数 15022 阅读 847

spring

1.spring是什么?

stuuts是web框架(jsp、zactionactionfrom)
hibernate是orm框架,处于持久层。
spring是容器框架,用于配置bean,并维护bean之间关系的框架
spring中有一个非常概念:bean是java中任何一种对象javabean、service、action,数据源,dao,ioc(控制反转inverse of control),di(dependency injection 依赖注入)

2.快速入门:

1.引入spring的开发包
2.创建spring的核心文件。applicationContext.xml该文件一般放在src目录下

3.在applicationContext.xml中配置bean

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!--
  3. - Middle tier application context definition for the image database.
  4. -->
  5. <beans xmlns="http://www.springframework.org/schema/beans"
  6. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  7. xmlns:context="http://www.springframework.org/schema/context"
  8. xmlns:tx="http://www.springframework.org/schema/tx"
  9. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  10. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
  11. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
  12. <!-- 在容器文件中配置bean -->
  13. <!-- bean元素作用 当我们spring框架加载时,spring就会自动创建一个bean -->
  14. <bean id="userService" class="com.service.UserService">
  15. <!-- 这里就是注入 -->
  16. <property name="name">
  17. <value>biaobiao</value>
  18. </property>
  19. </bean>
  20. </beans>

4.在Test.java中使用

  1. //1.得到spring容器的applicationContext对象(容器对象)
  2. ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  3. UserService us = (UserService) ac.getBean("userService");
  4. us.sayHello();

上面的功能等同于

  1. UserService us = new UserService();
  2. us.setName("biaobiao");
  3. us.sayHello();

注:
UserService.java

  1. package com.service;
  2. public class UserService {
  3. private String name;
  4. public String getName() {
  5. return name;
  6. }
  7. public void setName(String name) {
  8. this.name = name;
  9. }
  10. public void sayHello(){
  11. System.out.println("hello world " + name);
  12. }
  13. }

5.细节讨论
传统方法和使用spring方法
5.1 使用spring没有new对象,我们把创建对象那个的任务交给spring框架。

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");执行的时候,我们的spring容器对象被创建,同时,applicationContext.xml中配置的bean就会被创建。

3.spring运行原理:

【图片】

spring实际上是一个容器框架,可以配置各种bean,并且可以维护bean与bean的关系,我们需要使用某个bean的时候,我们可以getBean(id)使用即可。

IOC是什么:

ioc (inverse of controll)控制反转,控制反转就是把创建对象(bean),和维护对象(bean)的关系的权利从程序中转移到spring的容器中(applicationContext.xml),而程序本身不再维护。

DI是什么:

di(dependency injection)依赖注入:实际上di和ioc是同一个概念,spring设计者认为di更准确表示spring核心技术。

学习框架最重要的就是学习各个配置。

把ApplicationContext做成一个单例。

使用BeanFactory获取bean:

  1. //使用beanfactory获取bean
  2. BeanFactory bf = new XmlBeanFactory(new ClassPathResource("com/test/Beans.xml"));

我们使用beanfactory去获取bean,当实例化该容器的时候,该容器的bean不被实例化,只有当你去使用getBean某个bean时,才会实时的创建。好处就是节约内存,缺点就是速度比较慢。
(使用这句时ChangUpper cu = (ChangUpper) bf.getBean("ChangUpper");
才会被实例化。)

使用ApplicationContext获取bean

而使用ApplicationContext时,只要ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");这一句时bean就会被实例化。不管理用不用都被会实例化,好处就是可以预先加载,缺点就是耗费内存。

一般没有特殊要求,应当使用ApplicationContext完成。(90%)

bean scope:


singliton:单例,默认值(每次获取都都是同一个),在每个Spring IoC容器中一个bean定义对应一个对象实例。
prototype:原型(每次获取的都不是同一个),一个bean定义对应多个对象实例。
request:在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。
session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。

三种获取ApplicationContext应用的三种方法:

  1. ClassPathXmlApplicationContext--->通过类路径来获取
  1. ApplicationContext ac = new ClassPathXmlApplicationContext("com/test/Beans.xml");
  1. FileSystemXmlApplicationContext--->通过文件路径
  1. ApplicationContext ac = new FileSystemXmlApplicationContext("F:\\java\\work_1\\spring\\src\\com\\test\\Beans.xml");
  1. XmlWebApplicationContext

3.bean的生命周期:

  1. 实例化(当我们加载beans.xml文件是),把我们的bean(前提是scope=singleton)实例化到内存。
  2. 调用set()方法设置属性。
  3. 如果实现了bean名字关注接口(BeanNameAware),则可以通过调用setBeanName方法获取id。
  4. 如果你实现了bean工厂关注接口,则可以获取BeanFactory。
  5. 如果你是实现了ApplicationContextAware则调用方法
  1. public void setAplicationContext(ApplicationContext arg0) throws BeansException{
  2. .......
  3. }
  1. 如果bean和一个后置处理器关联,则会自动调用Object postProcessBeforeInitialization方法。
  2. 如果实现了InitializingBean接口,则会调用afterPropertiesSet方法
  3. 如果自己在则可以在bean中定义自己的初始化方法。
  4. 如果bean和一个后置处理器关联,则会自动调用Object postProcessAfterInitialization方法。
  5. 使用我们的Bean。
  6. 容器关闭。
  7. 可通过实现DisposableBean接口来调用destory方法。
  8. 可以在调用定制的销毁方法。

小结:我们实际开发中往往没有这么多过程。常见的是:
1-->2-->6-->9-->10-->11

通过BeanFactory来获取bean对象,bean的生命周期是否和ApplicationContext一样。
答:不一样,1-->2-->-->3-->7-->8-->10-->11-->12--13.

4.配置bean

如何给集合类型注入值:

  1. //Student.java
  2. package com.student;
  3. public class Student {
  4. private String name;
  5. private int age;
  6. public String getName() {
  7. return name;
  8. }
  9. public void setName(String name) {
  10. this.name = name;
  11. }
  12. public int getAge() {
  13. return age;
  14. }
  15. public void setAge(int age) {
  16. this.age = age;
  17. }
  18. }
  1. //Major.java
  2. package com.student;
  3. import java.util.List;
  4. import java.util.Map;
  5. import java.util.Set;
  6. public class Major {
  7. private String name;
  8. private List<Student> studentList;
  9. private Set<Student> studentSet;
  10. private Map<String, Student> studentMap;
  11. public Set<Student> getStudentSet() {
  12. return studentSet;
  13. }
  14. public void setStudentSet(Set<Student> studentSet) {
  15. this.studentSet = studentSet;
  16. }
  17. public String getName() {
  18. return name;
  19. }
  20. public void setName(String name) {
  21. this.name = name;
  22. }
  23. public List<Student> getStudentList() {
  24. return studentList;
  25. }
  26. public void setStudentList(List<Student> studentList) {
  27. this.studentList = studentList;
  28. }
  29. public Map<String, Student> getStudentMap() {
  30. return studentMap;
  31. }
  32. public void setStudentMap(Map<String, Student> studentMap) {
  33. this.studentMap = studentMap;
  34. }
  35. }
  1. //Bean.xml
  2. <?xml version="1.0" encoding="UTF-8"?>
  3. <!--
  4. - Middle tier application context definition for the image database.
  5. -->
  6. <beans xmlns="http://www.springframework.org/schema/beans"
  7. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  8. xmlns:context="http://www.springframework.org/schema/context"
  9. xmlns:tx="http://www.springframework.org/schema/tx"
  10. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  11. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
  12. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
  13. <bean id="student_1" class="com.student.Student">
  14. <property name="name">
  15. <value>王二小</value>
  16. </property>
  17. <property name="age">
  18. <value>23</value>
  19. </property>
  20. </bean>
  21. <bean id="student_2" class="com.student.Student">
  22. <property name="name">
  23. <value>张三丰</value>
  24. </property>
  25. <property name="age">
  26. <value>43</value>
  27. </property>
  28. </bean>
  29. <!-- List list中可以有相同的对象 -->
  30. <bean id="majorList" class="com.student.Major">
  31. <property name="name">
  32. <value>数学系</value>
  33. </property>
  34. <property name="studentList">
  35. <list>
  36. <ref bean="student_1"/>
  37. <ref bean="student_2"/>
  38. </list>
  39. </property>
  40. </bean>
  41. <!-- Set set中不能有相同的对象-->
  42. <bean id="majorSet" class="com.student.Major">
  43. <property name="name">
  44. <value>中文系</value>
  45. </property>
  46. <property name="studentSet">
  47. <set>
  48. <ref bean="student_1"/>
  49. <ref bean="student_2"/>
  50. </set>
  51. </property>
  52. </bean>
  53. <!-- Map -->
  54. <bean id="majorMap" class="com.student.Major">
  55. <property name="name">
  56. <value>英文系</value>
  57. </property>
  58. <property name="studentMap">
  59. <map>
  60. <entry key="2001" value-ref="student_1"/>
  61. <entry key="2002" value-ref="student_2"/>
  62. </map>
  63. </property>
  64. </bean>
  65. </beans>
  1. //Main测试函数
  2. package com.student;
  3. import java.util.Iterator;
  4. import java.util.Map;
  5. import java.util.Map.Entry;
  6. import org.springframework.context.ApplicationContext;
  7. import org.springframework.context.support.ClassPathXmlApplicationContext;
  8. public class Main {
  9. public static void main(String[] args) {
  10. ApplicationContext ac = new ClassPathXmlApplicationContext("com/student/Beans.xml");
  11. System.out.println("*************通过List取值**********");
  12. Major maList = (Major) ac.getBean("majorList");
  13. System.out.println("专业:" + maList.getName());
  14. for(Student stu: maList.getStudentList()){
  15. System.out.println(stu.getName()+ " " + stu.getAge());
  16. }
  17. System.out.println("*************通过set取值**********");
  18. Major maSet = (Major) ac.getBean("majorSet");
  19. System.out.println("专业:" + maSet.getName());
  20. for(Student stu: maSet.getStudentSet()){
  21. System.out.println(stu.getName()+ " " + stu.getAge());
  22. }
  23. System.out.println("*************通过Map取值**********");
  24. Major maMap = (Major) ac.getBean("majorMap");
  25. System.out.println("专业:" + maMap.getName());
  26. //迭代Map
  27. //1.迭代器
  28. Map<String, Student> stumap = maMap.getStudentMap();
  29. Iterator it = stumap.keySet().iterator();
  30. while(it.hasNext()){
  31. String key = (String)it.next();
  32. Student student = stumap.get(key);
  33. System.out.println(key + " " + student.getName() + " " + student.getAge());
  34. }
  35. //2.Entry
  36. for(Entry<String, Student> enMap:maMap.getStudentMap().entrySet() ){
  37. System.out.println(enMap.getKey() + " " +enMap.getValue().getName()+" " + enMap.getValue().getAge());
  38. }
  39. }
  40. }

内部bean使用方法:

  1. <bean id="foo" class=".....Foo>
  2. <property name=" 属性">
  3. <!--第一种方法引用-->
  4. <ref bean="bean对象名">
  5. <!--内部bean-->
  6. <bean>
  7. <property>
  8. </property>
  9. </bean>
  10. </property>
  11. </bean>

继承表示:

  1. <bean id="foo" parent="父类对象名" class=".....Foo>
  2. <property name=" 属性" value="值"/>
  3. </bean>

5.通过构造函数注入值

  1. public class ExampleBean {
  2. private int years;
  3. private String ultimateAnswer;
  4. public ExampleBean(int years, String ultimateAnswer) {
  5. this.years = years;
  6. this.ultimateAnswer = ultimateAnswer;
  7. }
  8. }

方法1.构造参数类型匹配

  1. <bean id="exampleBean" class="examples.ExampleBean">
  2. <constructor-arg type="int" value="7500000"/>
  3. <constructor-arg type="java.lang.String" value="42"/>
  4. </bean>

方法2.构造参数索引(通过使用索引属性不但可以解决多个简单属性的混淆问题,还可以解决有可能有相同类型的2个构造参数的混淆问题了,注意index是从0开始。

  1. <bean id="exampleBean" class="examples.ExampleBean">
  2. <constructor-arg index="0" value="7500000"/>
  3. <constructor-arg index="1" value="42"/>
  4. </bean>

6.自动装配

模式 说明
no
byName 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。例如,在bean定义中将autowire设置为by name,而该bean包含master属性(同时提供setMaster(..)方法),Spring就会查找名为master的bean定义,并用它来装配给master属性。
byType 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置dependency-check="objects"让Spring抛出异常。
constructor 与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
autodetect 通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。
  1. //Dog.java get/set方法略
  2. private String name;
  3. private int age;
  1. //Master.java
  2. private String name;
  3. private Dog dog;
  1. byname
  1. <bean id="master" class="com.autowire.Master" autowire="byName">
  2. <property name="name" value="朱元璋"></property>
  3. </bean>
  4. <bean id="dog" class="com.autowire.Dog">
  5. <property name="name" value="小黄"/>
  6. <property name="age" value="2"/>
  7. </bean>
  1. //测试
  2. ApplicationContext ac = new ClassPathXmlApplicationContext("com/autowire/Beans.xml");
  3. Master ma = (Master) ac.getBean("master");
  4. System.out.println(ma.getName() + " " + ma.getDog().getName());

上面例子可以看出,并没有配置master中的dog属性,但是还是可以直接取出,这是因为配置了autowire="byName";

  1. byType
    和byName类似,没有配置master中dog属性,但是如果是 autowire="byType",那么spring回首先在配置中去加载property配置,如果没有dog属性,再回在beans中寻找Dog类型的bean,如果有多个,会抛异常。

  2. constructor
    其他和byName类似,但是在Master类中,必须有以Dog为参数的构造函数。

  1. public Master(Dog dog) {
  2. this.dog = dog;
  3. }

4.autodetect

  1. defualt
  2. 这个需要在
    当你在指定了default-autowrite后,所有的bean的默认的autowire就是指定的装配方法
    如果没有在没有在这里指定,默认就是no。
  3. no
    不自动装配

7. 启动注解

  1. <context:annotation-config/>

该配置可以激活注解。

8.使用spring的特殊bean,完成分散配置。

  1. //DBUtil.java
  2. private String drivername;
  3. private String url;
  4. private String name;
  5. private String password;
  1. <!--Beans.xml-->
  2. <!-- 引入db.properties-->
  3. <context:property-placeholder location="classpath:com/properties/db.properties"/>
  4. <bean id="dbutil" class="com.properties.DBUtil">
  5. <property name="name" value="${name}"/>
  6. <property name="drivername" value="${drivername}"/>
  7. <property name="url" value="${url}"/>
  8. <property name="password" value="${password}"/>
  9. </bean>

db.properties

  1. name=root
  2. drivername=com.mysql.jdbc.Driver
  3. url=jdbc:mysql://localhost/conn
  4. password=1234

8. aop编程

1.aop说明

aop(aspect oriented programming)面向切面编程,是对一类对象或者所有对象编程。
核心是在不增加代码的基础上还增加功能。

2.实例说明

目标,在调用TestService的sayHello()方法之前进行日志书写。
步骤:

1. 定义接口

  1. public interface TestServiceInter {
  2. public void sayHello();
  3. }

2. 编写对象(被代理对象,即目标对象)

  1. //set/get方法略
  2. public class Test1Service implements TestServiceInter,TestServiceInter_2{
  3. private String name;
  4. @Override
  5. public void sayHello() {
  6. System.out.println("hello " + name);
  7. }
  8. }

3. 编写通知(前置通知:目标方法调用前调用)

  1. public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
  2. /**
  3. * paraMethod 调用的方法
  4. * paramArrayOfObject:给她方法传递的参数
  5. * paramObject:目标对象
  6. */
  7. @Override
  8. public void before(Method paramMethod, Object[] paramArrayOfObject, Object paramObject)
  9. throws Throwable {
  10. System.out.println("记录日志...." + paramMethod.getName());
  11. }
  12. }

4. 在beans.xml文件中配置

4.1 配置被代理对象
4.2 配置通知
4.3 配置代理对象,是ProxyFactoryBean的实例对象。
4.3.1 代理接口集
4.3.2 植入通知
4.3.3 配置被代理的对象

  1. <!-- 配置被代理的对象 -->
  2. <bean id="test1Service" class="com.aop.Test1Service">
  3. <property name="name" value="朱元璋"></property>
  4. </bean>
  5. <!-- 配置前置通知 -->
  6. <bean id="MyMethodBeforeAdvice" class="com.aop.MyMethodBeforeAdvice"></bean>
  7. <!-- 配置代理对象 -->
  8. <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
  9. <!-- 配置代理接口集 -->
  10. <property name="proxyInterfaces">
  11. <list>
  12. <value>com.aop.TestServiceInter</value>
  13. </list>
  14. </property>
  15. <!-- 把通知织入到代理对象 -->
  16. <property name="interceptorNames">
  17. <!-- 相当于把包MyMethodBeforeAdvice迁址通知和代理对象关联起来,我们
  18. 也可以把通知看成拦截器 -->
  19. <value>MyMethodBeforeAdvice</value>
  20. </property>
  21. <!-- 配置被代理的对象,可以指定 -->
  22. <property name="target" ref="test1Service"/>
  23. </bean>

3.其他通知类型

通知类型 接口 描述
Around org.aopalliance.intercept.MethodInterceptor 拦截对目标方法的调用
Before Org.springframeword.aop.MethodBeforeAdvice 在目标方法前调用
After org.springframework.aop.AfterReturningAdvice 在目标方法调用之后调用
Throws Org.springframework.aop.ThrowAdvice 在目标方法跑出异常时调用调用

(其他通知的使用方法和前置通知类似)
注:
环绕通知

  1. public class MyMethodInterceptor implements MethodInterceptor {
  2. /**
  3. * @环绕通知
  4. */
  5. @Override
  6. public Object invoke(MethodInvocation paramMethodInvocation) throws Throwable {
  7. System.out.println("环绕通知: 方法调用之前");
  8. Object obj = paramMethodInvocation.proceed();//如果没有这句和返回切入的方法将不会被调用
  9. System.out.println("环绕通知: 方法调用之后");
  10. return obj;
  11. }
  12. }

异常通知

  1. public class MyThrowAdvice implements ThrowsAdvice {
  2. public void afterThrowing(Method m,Object[] os, Object targt,Exception e){
  3. System.out.println("出事了~~ " + e.getMessage());
  4. }
  5. }

自定义通知切入点

  1. <!-- 配置前置通知切入点(值让某个特定的方法切入前置通知) 只让sayHello方法切入前置通知-->
  2. <bean id="MyMethodBeforeAdviceFilter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
  3. <property name="advice" ref="MyMethodBeforeAdvice"></property>
  4. <property name="mappedNames">
  5. <list>
  6. <value>sayHello</value>
  7. </list>
  8. </property>
  9. </bean>

在将MyMethodBeforeAdviceFilter织入到代理对象中就可以了。

所有配置总览表:

  1. <!-- 配置被代理的对象 -->
  2. <bean id="test1Service" class="com.aop.Test1Service">
  3. <property name="name" value="朱元璋"></property>
  4. </bean>
  5. <!-- 配置前置通知 -->
  6. <bean id="MyMethodBeforeAdvice" class="com.aop.MyMethodBeforeAdvice"></bean>
  7. <!-- 配置后置通知 -->
  8. <bean id="MyAfterReturningAdvice" class="com.aop.MyAfterReturningAdvice"></bean>
  9. <!-- 配置环绕通知 -->
  10. <bean id="MyMethodInterceptor" class="com.aop.MyMethodInterceptor"></bean>
  11. <!-- 配置异常通知 -->
  12. <bean id="MyThrowAdvice" class="com.aop.MyThrowAdvice"></bean>
  13. <!-- 配置前置通知切入点(值让某个特定的方法切入前置通知) -->
  14. <bean id="MyMethodBeforeAdviceFilter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
  15. <property name="advice" ref="MyMethodBeforeAdvice"></property>
  16. <property name="mappedNames">
  17. <list>
  18. <value>sayHello</value>
  19. </list>
  20. </property>
  21. </bean>
  22. <!-- 配置代理对象 -->
  23. <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
  24. <!-- 配置代理接口集 -->
  25. <property name="proxyInterfaces">
  26. <list>
  27. <value>com.aop.TestServiceInter</value>
  28. <value>com.aop.TestServiceInter_2</value>
  29. </list>
  30. </property>
  31. <!-- 把通知织入到代理对象 -->
  32. <property name="interceptorNames">
  33. <!-- 相当于把包MyMethodBeforeAdvice迁址通知和代理对象关联起来,我们
  34. 也可以把通知看成拦截器 -->
  35. <list>
  36. <!-- 使用自定义前置通知的切入点 -->
  37. <value>MyMethodBeforeAdviceFilter</value>
  38. <!-- <value>MyMethodBeforeAdvice</value> -->
  39. <value>MyAfterReturningAdvice</value>
  40. <value>MyMethodInterceptor</value>
  41. <value>MyThrowAdvice</value>
  42. </list>
  43. </property>
  44. <!-- 配置被代理的对象,可以指定 -->
  45. <property name="target" ref="test1Service"/>
  46. </bean>

问:在spring的aop中,当你通过代理对象实现了接口aop接口的时候,获取的ProxyFactoryBean是什么类型?
答:返回的是一个代理对象,如果目标对象实现了接口,则spring使用jdk动态代理技术,如果目标对象没有实现接口, 则spring使用CGLIB技术。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注