Spring
基礎概念
企業級系統
大規模:用戶數量多、數據規模大、功能衆多
性能和安全要求高
業務複雜
靈活應變
Java如何開發企業級應用
由EJB到Spring
Spring
輕量級框架, Java EE的春天,當前主流框架
目標:使現有技術更加易用,推進編碼最佳實踐
內容:IoC容器、AOP實現
數據訪問支持:簡化JDBC/ORM 框架、聲明式事務
Web集成:可以和web框架集成
spring的體系結構
Spring設計理念—面向Bean的編程
Spring 兩大核心技術
控制反轉(IoC:Inversion of Control ) /依賴注入(DI:Dependency Injection )
面向切面編程(AOP:Aspect Oriented Programming)
Spring的優點
低侵入式設計
獨立於各種應用服務器
依賴注入特性將組件關係透明化,降低了耦合度
面向切面編程特性允許將通用任務進行集中式處理
與第三方框架的良好整合
實現
設計模式-簡單工廠
組件對象的控制權從代碼本身轉移到外部容器
組件化的思想:分離關注點,使用接口,不再關注實現
依賴的注入:將組件的構建和使用分開,只關注組件內部的事情
這個工廠能夠生產同一種類型的不同對象(下面同一個接口類型或者父類)
1、創建一個接口
package spring.cwj.sinple;
public interface Fruit {
void getName();
}
2、創建實體類
package spring.cwj.sinple;
public class Apple implements Fruit {
@Override
public String getName() {
return "蘋果";
}
}
package spring.cwj.sinple;
public class Pear implements Fruit {
@Override
public String getName() {
return "梨子 ";
}
}
工廠類
package spring.cwj.sinple;
public class FruitFactory {
public static Fruit createInstance(String type) {
Fruit fruit=null;
switch(type) {
case"apple":
fruit=new Apple();
break;
case"pear":
fruit=new Pear();
}
return fruit;
}
}
測試類
package spring.cwj.sinple;
import java.util.Scanner;
public class Test {
static Scanner input=new Scanner(System.in);
public static void main(String[] args) {
System.out.println("請輸入水果類型:");
String type=input.next();
Fruit f=FruitFactory.createInstance(type);
System.out.println(f.getName());
}
}
如果這時想要新增水果類型呢?
只需要新增一個桃子類,且在工廠類裏新增一個case
package spring.cwj.sinple;
public class Peach implements Fruit {
@Override
public String getName() {
return "桃子";
}
}
新增case
case"peach":
fruit=new Peach();
優點:代碼維護起來更容易
使用spring實現控制反轉(IOC)
編寫Hello類,輸出“Hello,xxx!”
字符串“Spring”通過Spring注入到Hello類中
1、新建一個Java項目springTest,創建一個hello類
package spring.cwj.pojo;
public class Hello {
private String hello;
public String getHello() {
return hello;
}
public void setHello(String hello) {
this.hello = hello;
}
public void print() {
System.out.println("你好"+this.hello);
}
}
2、新建lib文件夾導入loggin 、core、context、beans、expression四個jar包
注意,這個不是web項目,需要手動build path
3、創建一個applicationContext.xml
配置文件放到資源文件夾(建議配置文件命名applicationContext)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- bean就是對象,class=“包名.類名”-->
<bean id="hello" class="spring.cwj.pojo.Hello">
<!--注入,通過name=“屬性名”就是實體類的一個屬性名,然後注入值value-->
<property name="hello" value="張三"></property>
</bean>
</beans>
package spring.cwj.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring.cwj.pojo.Hello;
public class Test {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//使用bean創建了一個對象
Hello h=(Hello)ctx.getBean("hello");
//用對象調用Hello類的方法
h.print();
}
}
注:設值注入是通過set方法注入,set後面小寫等於name=“值”
如果沒有set方法就無法注入
public void setXxx(String hello) {
this.hello = hello;
}
<bean id="hello" class="spring.cwj.pojo.Hello">
<property name="xxx" value="張三"></property>
</bean>
測試類調用的是bean的id"hello",property的name是設值注入
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
Hello o=(Hello)ctx.getBean("hello");
o.print();
理解Spring IoC的原理
1、設值注入
2、使用元素定義一個組件
id屬性:指定一個用來訪問的唯一名稱
name屬性:指定多個別名,名字之間使用逗號、分號或空格進行分隔(id和name不能和其他id和name和類名一樣)
<bean id="hello" name="haha,hehe" class="spring.cwj.pojo.Hello">
<property name="xxx" value="張三"></property>
</bean>
測試類
Hello h=(Hello)ctx.getBean("haha");
h.print();
掌握Spring IoC的配置
開發一個打印機
可靈活配置使用彩色墨盒或灰色墨盒
可靈活配置打印頁面的大小
打印機功能的實現依賴於墨盒和紙張
步驟
定義墨盒和紙張的接口標準
package spring.cwj.print;
/**
* @墨盒顏色
*/
public interface InkBox {
String getColor();
}
package spring.cwj.print;
/**
* @紙張大小
*/
public interface Paper {
String size();
}
使用接口標準開發打印機
package spring.cwj.print;
public class ColorInkBox implements InkBox {
@Override
public String getColor() {
return "彩色";
}
}
package spring.cwj.print;
public class GrayInkBox implements InkBox {
@Override
public String getColor() {
return "灰白";
}
}
package spring.cwj.print;
public class A4Paper implements Paper {
@Override
public String size() {
return "A4";
}
}
package spring.cwj.print;
public class B5Paper implements Paper {
@Override
public String size() {
return "B5";
}
}
組裝打印機
package spring.cwj.print;
public class Printer {
private InkBox inkBox;
private Paper paper;
public InkBox getInkBox() {
return inkBox;
}
public void setInkBox(InkBox inkBox) {
this.inkBox = inkBox;
}
public Paper getPaper() {
return paper;
}
public void setPaper(Paper paper) {
this.paper = paper;
}
public void print() {
System.out.println(this.inkBox.getColor()+"打印在"+this.paper.size());
}
}
配置文件
<bean id="colorInkBox" class="spring.cwj.print.ColorInkBox" />
<bean id="grayInkBox" class="spring.cwj.print.GrayInkBox" />
<bean id="a4Paper" class="spring.cwj.print.A4Paper" />
<bean id="b5paper" class="spring.cwj.print.B5Paper" />
<bean id="print" class="spring.cwj.print.Printer">
<property name="inkBox" ref="grayInkBox"></property>
<property name="paper" ref="b5paper"></property>
</bean>
測試類
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
Printer p=(Printer)ctx.getBean("print");
p.print();
}
理解Spring AOP的原理
將複雜的需求分解出不同方面,將散佈在系統中的公共功能集中解決
採用代理機制組裝起來運行,在不改變原程序的基礎上對代碼段進行增強處理,增加新的功能
所謂面向切面編程,是一種通過預編譯和運行期動態代理的方式實現在不修改源代碼的情況下給程序動態添加功能的技術
通過代理對象來調用原對象的方法,代理對象方法前後都可插入代碼,這些代碼就是增強處理
代理模式
原代碼
package spring.cwj.tar;
public class Target {
public void test() {
System.out.println("target");
}
}
直接調用目標方法
package spring.cwj.tar;
public class TestAop {
public static void main(String[] args) {
Target t=new Target();
t.test();
}
}
代理模式:讓別人幫自己操作
創建代理類
package spring.cwj.tar;
public class TargetProxy {
private Target target=new Target();
public void test() {
target.test();
}
}
測試類
TargetProxy tp=new TargetProxy();
tp.test();
優點:
可以在代理類添加任何想要添加的東西
如果目標類出現異常,可以在代理類處理
可以在代理類執行一些別的操作
package spring.cwj.tar;
public class TargetProxy {
private Target target=new Target();
public void test() {
try {
System.out.println("前置增強");
target.test();
System.out.println("後置增強");
}catch(Exception e) {
System.out.println("異常增強");
}finally {
System.out.println("最終增強");
}
}
}
出現異常的情況
public class Target {
public void test() {
//分母不得爲0
int i=2/0;
System.out.println("target");
}
}
AOP相關術語
增強處理(Advice):增加一些代碼
前置增強Before、後置增強AfterReturning、異常拋出增強、最終增強
環繞增強(包括以上4中增強)
切入點(Pointcut):目標方法就是一種切入點
連接點(Join Point)
切面(Aspect):增強和切入點結合形成
目標對象(Target object):被調用執行的對象
AOP代理(AOP proxy)
織入(Weaving):把代理的代碼調用到目標方法的過程
掌握Spring AOP的配置
1、導入aop的jar包(3個)
1、目標類
package spring.cwj.tar;
public class Target {
public void test() {
System.out.println("target");
}
}
2、代理類
注意不要導錯包import org.aspectj.lang.JoinPoint;
package spring.cwj.tar;
import org.aspectj.lang.JoinPoint;
public class MyProxy {
public void before(JoinPoint jp) {
System.out.println("前置增強");
}
}
3、配置文件
<!--給目標類和代理類創建對象-->
<bean id="myProxy" class="spring.cwj.tar.MyProxy"></bean>
<bean id="target" class="spring.cwj.tar.Target"></bean>
<aop:config>
<!--給一個公共的返回值爲空,方法名爲test,沒有參數的方法,只要調用這個方法,在調用之前前置增強-->
<aop:pointcut expression="execution(public void test())" id="pointcut"/>
<!--切面-->
<aop:aspect ref="myProxy">
<!--切面:method="before"對應代理類的方法名,pointcut-ref="pointcut"對應切點-->
<aop:before method="before" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
4、測試類
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
Target t=(Target)ctx.getBean("target");
t.test();
可以通過代理類得到一些目標方法的信息
public void before(JoinPoint jp) {
System.out.println("前置增強"+jp.getSignature().getName());
}
定義切入點