Spring基础知识小结
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(); (..)表示任意个参数