Spring学习笔记
第一章 初识Spring
Spring是轻量级的JAVA EE框架。Spring以IOC/DI、AOP为核心思想。其中,IOC是指控制反转或者反向
控制,AOP是指切面编程。在Spring框架中,我们通过配置来创建类的对象,由Spring在运行阶段实例
化,组装对象,这叫控制反转;在执行一段代码之前或者之后或者同时,执行另一代段码,使程序更加
灵活,扩展性更好,这叫切面编程。
控制反转
既然有反转,那么自然会有与之对应的"正转"。例如class A中有一个依赖类class B,即在class A中
需要调用class B。
public class A{
public void add(){
B b = new B();
}
}
在这里,我们手动new了class B。这是常规的,也就叫"正转"。那么"反转"就是将类交给Spring管理,
当需要的时候,spring会自动创建一个类,这就是反转。
例如:
教师类:
public class Techer {
private String name;
public void teach(){
System.out.println("我是人名教师!");
}
}
applicationContext.xml中:
<bean id="techer" class="com.xt.beans.Techer"></bean>
测试类:
public static void main(String[] args) {
String[] paths = new String[]{"spring/applicationContext.xml"};
BeanFactory bf = new ClassPathXmlApplicationContext(paths);
Techer techer = (Techer) bf.getBean("techer");
techer.teach();
}
很显然,在测试类中,我们并没有手动new Techer(),而是从Bean工厂中取的。这就是控制反转。
第二章 Spring的三种注入方式以及自动注入
在第一章说道,使用Spring来管理类。让Spring来创建类的对象,既然如此,那自然要对类中的属性
进行赋值。在Spring中,为类放入属性赋值有三种方式:设值注入、构造注入、接口注入。
1.设值注入
设值注入其实就是通过类中的setter()方法对属性进行赋值。
例如:
学生类
Student.class:
package com.xt.beans;
public class Student {
private Integer id;
private String stuName;
private Integer age;
private String address;
public Student(Integer id, String stuName, Integer age, String address) {
super();
this.id = id;
this.stuName = stuName;
this.age = age;
this.address = address;
}
public Student() {
super();
}
setter()/getter()......
public void game(){
System.out.println("我叫"+this.stuName+",我今年"+this.age+"岁了。我家住在"+this.address);
}
}
applicationContext.xml中:
<bean id="student" class="com.xt.beans.Student">
<!--设值注入-->
<property name="stuName" value="张三"></property>
<property name="age" value="22"></property>
<property name="age" value="24"></property>
<property name="address" value="湖北省十堰市"></property>
</bean>
测试类:
public static void main(String[] args) {
String paths[] = new String[]{"spring/applicationContext.xml"};
BeanFactory bf = new ClassPathXmlApplicationContext(paths);
Student student1 = (Student) bf.getBean("student");
Student student2 = (Student) bf.getBean("student");
System.out.println(student1==student2);
student1.game();
student2.game();
}
运行结果:
true
我叫张三,我今年24岁了。我家住在湖北省十堰市
我叫张三,我今年24岁了。我家住在湖北省十堰市
解析:
(1).在applicationContext.xml中,我们通过<property>标签为Student类中的属性进行赋值,这就是
设值注入。
(2).从运行结果来看,spring默认为单态模式。在测试类中,我们可以看出,student1和student2是同
一个对象,这就充分说明Spring默认为单例模式。那么自然而然就有多态模式,如何让其变为多态模式?
在<bean>中有一个属性:scope。
scoped的取值有:
default:默认单例模式
prototype:多态模式
session:在Spring创建对象后,会将对象放入session中
(3).将模式变为多态模式:
<bean id="student" scope="prototype" class="com.xt.beans.Student">
........
</bean>
运行结果:
false <---------------
我叫张三,我今年24岁了。我家住在湖北省十堰市
我叫张三,我今年24岁了。我家住在湖北省十堰市
2.构造注入(标签:<constructor-arg>)
顾名思义,通过类的构造方法对属性进行赋值。所以,类中要有有参构造方法。
例如:
学生类Student.class
同上.......
applicationContext.xml中:
<bean id="student" class="com.xt.beans.Student">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="stuName" value="张三"></constructor-arg>
<constructor-arg name="age" value="23"></constructor-arg>
<constructor-arg name="address" value="上海市宝山区"></constructor-arg>
</bean>
3.接口注入
当一个类A中需要另一个类B的方法来实现某些功能的时候,我们说A依赖于B。在这种情况下,我们
通常定义个接口IC,并让类B实现IC。
例如:
孩子类Child.class:
public class Child {
private IParents parents;
setter()/getter()......
public Child(IParents parents){
this.parents = parents;
}
}
接口:
public interface IParents {
public void print() throws Exception;
}
妈妈类:
public class Mother implements IParents{
public void print(){
System.out.println("我是孩子妈妈.....");
}
}
爸爸类:
public class Father implements IParents {
public void print() throws Exception {
System.out.println("我是孩子爸爸......");
}
}
applicationContext.xml中:
<bean id="mother" class="com.xt.beans.Mother"></bean>
<bean id="father" class="com.xt.beans.Father"></bean>
<bean id="child" class="com.xt.beans.Child">
<constructor-arg name="parents" ref="father"></constructor-arg>
</bean>
4.自动注入(byName/byType)
在之前的学习过程中,我们都是显示注入,即ref="".其实在Spring中,还为我们提供了自动注入方式。
有两种:byType、byName.
(1).byType 根据类型注入
在Child中,需要一个接口IParents。该接口下有两个实现类,分别是:Mother / Father 。
那么Mother / Father 都属于IParents类型。
所以,在注入的时候,我们不需要再通过ref="mother"或者ref="father"来显示输入。而可以通过
<bean autowire="byType"></bean>来根据类型注入。
代码:
applicationContext.xml中:
<!--<bean id="mother" class="com.xt.beans.Mother"></bean>-->
<bean id="father" class="com.xt.beans.Father"></bean>
<bean id="child" class="com.xt.beans.Child" autowire="byType"></bean>
运行结果:
我是孩子爸爸......
注:
在上面的代码中,我们可以看出将id="father"注入到了Child 中。在使用byType自动注入的
时候,如果有两个及两个以上都属于同一种类型,即:多个类实现了同一个接口时,使用byType
会报错!因为不知道具体要注入哪一个.
(2).byName 通过名称自动注入
在Child中,需要一个接口IParents parents。该接口下有两个实现类,分别是:Mother / Father 。
如果在applicationContext.xml中,有bean的id与parents相同,通过autowire="byName"就会自动注入。
代码:
<bean id="mother" class="com.xt.beans.Mother"></bean>
<bean id="parents" class="com.xt.beans.Father"></bean>
<bean id="child" class="com.xt.beans.Child" autowire="byName"></bean>
运行结果:
我是孩子的爸爸......
第三章 切面编程AOP
在开发过程中,我们经常会遇到这种情况:在调用一个方法之前,希望系统能自动调用另一个方法;或者是执行
完一个方法后,希望系统能自动调用另一个方法;或者是同时调用。。。。。当然我们可以手动去
调用,但是这不方便。在Spring中,,为我们提供了面向切面编程的一种编程方式,让我们不用手动调用,而是
当方法执行完成后,系统自己完成方法的执行。
我们设想一个场景:
某个大型商场刚刚开业,商品都打折,吸引顾客。小明听说后,也去了商场购物。当他刚进商场大门时,喇叭里
说道:"欢迎光临!祝您购物愉快!"小明于是高高兴兴走了进去,买了一大堆打折商品区结账。此时喇叭里又说
道:"您此次消费1000元!"小明结了账后,走出商场,此时喇叭又说道:"欢迎下次光临!"
我们可以把以上场景抽象为:
(1).小明购物对应Custom类中的方法buy()
(2).喇叭播放"欢迎光临"对应的是SuperMarket类中的方法welcome()
(3).喇叭播放"您此次消费1000元!"对应的是SuperMarket类中的方法shouldPay()
(4).喇叭播放"欢迎下次光临!"对应的是SuperMarket类中的方法sayGoodBy()
那么我们现在要做的就是,在执行buy()之前,执行welcome();在执行buy()之后,执行sayGoodBy();
在执行buy()同时,执行shouldPay()。
那如何用切面编程来完成呢?
1.导入相应的jar包
spring-aop.jar、aspectjweaver.jar、aspectjrt.jar
2.Custom类:
public class Custom {
private BigDecimal payMoney;
public BigDecimal getPayMoney() {
return payMoney;
}
public void setPayMoney(BigDecimal payMoney) {
this.payMoney = payMoney;
}
public void buy(){
System.out.println("我来购物啦!");
}
}
(3).SuperMarket类:
public class SuperMarket {
public void welcome(){
System.out.println("欢迎光临!祝您购物愉快!");
}
public void shouldPay(JoinPoint point){
Custom customer = (Custom) point.getTarget();
System.out.println("您需要支付"+customer.getPayMoney()+"元。");
}
public void sayGoodBy(){
System.out.println("欢迎下次光临!");
}
}
(4).applicationContext中的:
<bean id="custom" class="com.xt.superMarket.Custom">
<property name="payMoney" value="1000"></property>
</bean>
<bean id="market" class="com.xt.superMarket.SuperMarket"></bean>
<!-- aop配置 -->
<aop:config>
<!-- 配置切面 -->
<aop:aspect id="supermarket" ref="market">
<!-- 配置切点 -->
<aop:pointcut id="pointcut" expression="execution(* com.xt.superMarket.Custom.*(..))"></aop:pointcut>
<!-- 配置通知方式 -->
<!-- 前置通知 -->
<aop:before method="welcome" pointcut-ref="pointcut"></aop:before>
<!-- 环绕通知 -->
<aop:around method="shouldPay" pointcut-ref="pointcut"></aop:around>
<!-- 后置通知 -->
<aop:after method="sayGoodBy" pointcut-ref="pointcut"></aop:after>
</aop:aspect>
</aop:config>
解析:
(1).<aop:pointcut id="pointcut" expression="execution(* com.xt.superMarket.Custom.*(..))"></aop:pointcut>
配置切点
第一个*代表:任意返回类型,这里是void;
第二个*是任意方法,这里是buy();
(..)表示任意个参数