@snail-lb
2016-07-22T13:36:51.000000Z
字数 15022
阅读 1055
stuuts是web框架(jsp、zactionactionfrom)
hibernate是orm框架,处于持久层。
spring是容器框架,用于配置bean,并维护bean之间关系的框架
spring中有一个非常概念:bean是java中任何一种对象javabean、service、action,数据源,dao,ioc(控制反转inverse of control),di(dependency injection 依赖注入)
1.引入spring的开发包
2.创建spring的核心文件。applicationContext.xml该文件一般放在src目录下
3.在applicationContext.xml中配置bean
<?xml version="1.0" encoding="UTF-8"?><!--- Middle tier application context definition for the image database.--><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"><!-- 在容器文件中配置bean --><!-- bean元素作用 当我们spring框架加载时,spring就会自动创建一个bean --><bean id="userService" class="com.service.UserService"><!-- 这里就是注入 --><property name="name"><value>biaobiao</value></property></bean></beans>
4.在Test.java中使用
//1.得到spring容器的applicationContext对象(容器对象)ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");UserService us = (UserService) ac.getBean("userService");us.sayHello();
上面的功能等同于
UserService us = new UserService();us.setName("biaobiao");us.sayHello();
注:
UserService.java
package com.service;public class UserService {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void sayHello(){System.out.println("hello world " + name);}}
5.细节讨论
传统方法和使用spring方法
5.1 使用spring没有new对象,我们把创建对象那个的任务交给spring框架。
当ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");执行的时候,我们的spring容器对象被创建,同时,applicationContext.xml中配置的bean就会被创建。
【图片】
spring实际上是一个容器框架,可以配置各种bean,并且可以维护bean与bean的关系,我们需要使用某个bean的时候,我们可以getBean(id)使用即可。
ioc (inverse of controll)控制反转,控制反转就是把创建对象(bean),和维护对象(bean)的关系的权利从程序中转移到spring的容器中(applicationContext.xml),而程序本身不再维护。
di(dependency injection)依赖注入:实际上di和ioc是同一个概念,spring设计者认为di更准确表示spring核心技术。
学习框架最重要的就是学习各个配置。
把ApplicationContext做成一个单例。
//使用beanfactory获取beanBeanFactory bf = new XmlBeanFactory(new ClassPathResource("com/test/Beans.xml"));
我们使用beanfactory去获取bean,当实例化该容器的时候,该容器的bean不被实例化,只有当你去使用getBean某个bean时,才会实时的创建。好处就是节约内存,缺点就是速度比较慢。
(使用这句时ChangUpper cu = (ChangUpper) bf.getBean("ChangUpper");
才会被实例化。)
而使用ApplicationContext时,只要ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");这一句时bean就会被实例化。不管理用不用都被会实例化,好处就是可以预先加载,缺点就是耗费内存。
一般没有特殊要求,应当使用ApplicationContext完成。(90%)
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 ac = new ClassPathXmlApplicationContext("com/test/Beans.xml");
ApplicationContext ac = new FileSystemXmlApplicationContext("F:\\java\\work_1\\spring\\src\\com\\test\\Beans.xml");
public void setAplicationContext(ApplicationContext arg0) throws BeansException{.......}
小结:我们实际开发中往往没有这么多过程。常见的是:
1-->2-->6-->9-->10-->11
通过BeanFactory来获取bean对象,bean的生命周期是否和ApplicationContext一样。
答:不一样,1-->2-->-->3-->7-->8-->10-->11-->12--13.
如何给集合类型注入值:
//Student.javapackage com.student;public class Student {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;}}
//Major.javapackage com.student;import java.util.List;import java.util.Map;import java.util.Set;public class Major {private String name;private List<Student> studentList;private Set<Student> studentSet;private Map<String, Student> studentMap;public Set<Student> getStudentSet() {return studentSet;}public void setStudentSet(Set<Student> studentSet) {this.studentSet = studentSet;}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<Student> getStudentList() {return studentList;}public void setStudentList(List<Student> studentList) {this.studentList = studentList;}public Map<String, Student> getStudentMap() {return studentMap;}public void setStudentMap(Map<String, Student> studentMap) {this.studentMap = studentMap;}}
//Bean.xml<?xml version="1.0" encoding="UTF-8"?><!--- Middle tier application context definition for the image database.--><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"><bean id="student_1" class="com.student.Student"><property name="name"><value>王二小</value></property><property name="age"><value>23</value></property></bean><bean id="student_2" class="com.student.Student"><property name="name"><value>张三丰</value></property><property name="age"><value>43</value></property></bean><!-- List list中可以有相同的对象 --><bean id="majorList" class="com.student.Major"><property name="name"><value>数学系</value></property><property name="studentList"><list><ref bean="student_1"/><ref bean="student_2"/></list></property></bean><!-- Set set中不能有相同的对象--><bean id="majorSet" class="com.student.Major"><property name="name"><value>中文系</value></property><property name="studentSet"><set><ref bean="student_1"/><ref bean="student_2"/></set></property></bean><!-- Map --><bean id="majorMap" class="com.student.Major"><property name="name"><value>英文系</value></property><property name="studentMap"><map><entry key="2001" value-ref="student_1"/><entry key="2002" value-ref="student_2"/></map></property></bean></beans>
//Main测试函数package com.student;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main {public static void main(String[] args) {ApplicationContext ac = new ClassPathXmlApplicationContext("com/student/Beans.xml");System.out.println("*************通过List取值**********");Major maList = (Major) ac.getBean("majorList");System.out.println("专业:" + maList.getName());for(Student stu: maList.getStudentList()){System.out.println(stu.getName()+ " " + stu.getAge());}System.out.println("*************通过set取值**********");Major maSet = (Major) ac.getBean("majorSet");System.out.println("专业:" + maSet.getName());for(Student stu: maSet.getStudentSet()){System.out.println(stu.getName()+ " " + stu.getAge());}System.out.println("*************通过Map取值**********");Major maMap = (Major) ac.getBean("majorMap");System.out.println("专业:" + maMap.getName());//迭代Map//1.迭代器Map<String, Student> stumap = maMap.getStudentMap();Iterator it = stumap.keySet().iterator();while(it.hasNext()){String key = (String)it.next();Student student = stumap.get(key);System.out.println(key + " " + student.getName() + " " + student.getAge());}//2.Entryfor(Entry<String, Student> enMap:maMap.getStudentMap().entrySet() ){System.out.println(enMap.getKey() + " " +enMap.getValue().getName()+" " + enMap.getValue().getAge());}}}
内部bean使用方法:
<bean id="foo" class=".....Foo><property name=" 属性"><!--第一种方法引用--><ref bean="bean对象名"><!--内部bean--><bean><property></property></bean></property></bean>
继承表示:
<bean id="foo" parent="父类对象名" class=".....Foo><property name=" 属性" value="值"/></bean>
public class ExampleBean {private int years;private String ultimateAnswer;public ExampleBean(int years, String ultimateAnswer) {this.years = years;this.ultimateAnswer = ultimateAnswer;}}
方法1.构造参数类型匹配
<bean id="exampleBean" class="examples.ExampleBean"><constructor-arg type="int" value="7500000"/><constructor-arg type="java.lang.String" value="42"/></bean>
方法2.构造参数索引(通过使用索引属性不但可以解决多个简单属性的混淆问题,还可以解决有可能有相同类型的2个构造参数的混淆问题了,注意index是从0开始。
)
<bean id="exampleBean" class="examples.ExampleBean"><constructor-arg index="0" value="7500000"/><constructor-arg index="1" value="42"/></bean>
| 模式 | 说明 |
|---|---|
| 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方式。 |
//Dog.java get/set方法略private String name;private int age;
//Master.javaprivate String name;private Dog dog;
<bean id="master" class="com.autowire.Master" autowire="byName"><property name="name" value="朱元璋"></property></bean><bean id="dog" class="com.autowire.Dog"><property name="name" value="小黄"/><property name="age" value="2"/></bean>
//测试ApplicationContext ac = new ClassPathXmlApplicationContext("com/autowire/Beans.xml");Master ma = (Master) ac.getBean("master");System.out.println(ma.getName() + " " + ma.getDog().getName());
上面例子可以看出,并没有配置master中的dog属性,但是还是可以直接取出,这是因为配置了autowire="byName";
byType
和byName类似,没有配置master中dog属性,但是如果是 autowire="byType",那么spring回首先在配置中去加载property配置,如果没有dog属性,再回在beans中寻找Dog类型的bean,如果有多个,会抛异常。
constructor
其他和byName类似,但是在Master类中,必须有以Dog为参数的构造函数。
public Master(Dog dog) {this.dog = dog;}
4.autodetect
<context:annotation-config/>
该配置可以激活注解。
//DBUtil.javaprivate String drivername;private String url;private String name;private String password;
<!--Beans.xml--><!-- 引入db.properties--><context:property-placeholder location="classpath:com/properties/db.properties"/><bean id="dbutil" class="com.properties.DBUtil"><property name="name" value="${name}"/><property name="drivername" value="${drivername}"/><property name="url" value="${url}"/><property name="password" value="${password}"/></bean>
db.properties
name=rootdrivername=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost/connpassword=1234
aop(aspect oriented programming)面向切面编程,是对一类对象或者所有对象编程。
核心是在不增加代码的基础上还增加功能。
目标,在调用TestService的sayHello()方法之前进行日志书写。
步骤:
public interface TestServiceInter {public void sayHello();}
//set/get方法略public class Test1Service implements TestServiceInter,TestServiceInter_2{private String name;@Overridepublic void sayHello() {System.out.println("hello " + name);}}
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {/*** paraMethod 调用的方法* paramArrayOfObject:给她方法传递的参数* paramObject:目标对象*/@Overridepublic void before(Method paramMethod, Object[] paramArrayOfObject, Object paramObject)throws Throwable {System.out.println("记录日志...." + paramMethod.getName());}}
4.1 配置被代理对象
4.2 配置通知
4.3 配置代理对象,是ProxyFactoryBean的实例对象。
4.3.1 代理接口集
4.3.2 植入通知
4.3.3 配置被代理的对象
<!-- 配置被代理的对象 --><bean id="test1Service" class="com.aop.Test1Service"><property name="name" value="朱元璋"></property></bean><!-- 配置前置通知 --><bean id="MyMethodBeforeAdvice" class="com.aop.MyMethodBeforeAdvice"></bean><!-- 配置代理对象 --><bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"><!-- 配置代理接口集 --><property name="proxyInterfaces"><list><value>com.aop.TestServiceInter</value></list></property><!-- 把通知织入到代理对象 --><property name="interceptorNames"><!-- 相当于把包MyMethodBeforeAdvice迁址通知和代理对象关联起来,我们也可以把通知看成拦截器 --><value>MyMethodBeforeAdvice</value></property><!-- 配置被代理的对象,可以指定 --><property name="target" ref="test1Service"/></bean>
| 通知类型 | 接口 | 描述 |
|---|---|---|
| Around | org.aopalliance.intercept.MethodInterceptor | 拦截对目标方法的调用 |
| Before | Org.springframeword.aop.MethodBeforeAdvice | 在目标方法前调用 |
| After | org.springframework.aop.AfterReturningAdvice | 在目标方法调用之后调用 |
| Throws | Org.springframework.aop.ThrowAdvice | 在目标方法跑出异常时调用调用 |
(其他通知的使用方法和前置通知类似)
注:
环绕通知
public class MyMethodInterceptor implements MethodInterceptor {/*** @环绕通知*/@Overridepublic Object invoke(MethodInvocation paramMethodInvocation) throws Throwable {System.out.println("环绕通知: 方法调用之前");Object obj = paramMethodInvocation.proceed();//如果没有这句和返回切入的方法将不会被调用System.out.println("环绕通知: 方法调用之后");return obj;}}
异常通知
public class MyThrowAdvice implements ThrowsAdvice {public void afterThrowing(Method m,Object[] os, Object targt,Exception e){System.out.println("出事了~~ " + e.getMessage());}}
自定义通知切入点
<!-- 配置前置通知切入点(值让某个特定的方法切入前置通知) 只让sayHello方法切入前置通知--><bean id="MyMethodBeforeAdviceFilter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"><property name="advice" ref="MyMethodBeforeAdvice"></property><property name="mappedNames"><list><value>sayHello</value></list></property></bean>
在将MyMethodBeforeAdviceFilter织入到代理对象中就可以了。
所有配置总览表:
<!-- 配置被代理的对象 --><bean id="test1Service" class="com.aop.Test1Service"><property name="name" value="朱元璋"></property></bean><!-- 配置前置通知 --><bean id="MyMethodBeforeAdvice" class="com.aop.MyMethodBeforeAdvice"></bean><!-- 配置后置通知 --><bean id="MyAfterReturningAdvice" class="com.aop.MyAfterReturningAdvice"></bean><!-- 配置环绕通知 --><bean id="MyMethodInterceptor" class="com.aop.MyMethodInterceptor"></bean><!-- 配置异常通知 --><bean id="MyThrowAdvice" class="com.aop.MyThrowAdvice"></bean><!-- 配置前置通知切入点(值让某个特定的方法切入前置通知) --><bean id="MyMethodBeforeAdviceFilter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"><property name="advice" ref="MyMethodBeforeAdvice"></property><property name="mappedNames"><list><value>sayHello</value></list></property></bean><!-- 配置代理对象 --><bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"><!-- 配置代理接口集 --><property name="proxyInterfaces"><list><value>com.aop.TestServiceInter</value><value>com.aop.TestServiceInter_2</value></list></property><!-- 把通知织入到代理对象 --><property name="interceptorNames"><!-- 相当于把包MyMethodBeforeAdvice迁址通知和代理对象关联起来,我们也可以把通知看成拦截器 --><list><!-- 使用自定义前置通知的切入点 --><value>MyMethodBeforeAdviceFilter</value><!-- <value>MyMethodBeforeAdvice</value> --><value>MyAfterReturningAdvice</value><value>MyMethodInterceptor</value><value>MyThrowAdvice</value></list></property><!-- 配置被代理的对象,可以指定 --><property name="target" ref="test1Service"/></bean>
问:在spring的aop中,当你通过代理对象实现了接口aop接口的时候,获取的ProxyFactoryBean是什么类型?
答:返回的是一个代理对象,如果目标对象实现了接口,则spring使用jdk动态代理技术,如果目标对象没有实现接口, 则spring使用CGLIB技术。