Spring 实践 -IoC
標(biāo)簽: Java與設(shè)計模式
Spring簡介
Spring是分層的JavaSE/EE Full-Stack輕量級開源框架.以IoC(Inverse of Control 控制反轉(zhuǎn))和AOP(Aspect Oriented Programming 面向切面編程)為內(nèi)核, 取代EJB的臃腫/低效/脫離現(xiàn)實.
主頁http://spring.io/
IoC與DI
- IOC: 即控制反轉(zhuǎn), 解決程序?qū)ο缶o密耦合問題(方式: 工廠+反射+配置文件), 將程序中原來構(gòu)造對象的操作,交給IoC容器, 當(dāng)程序真正需要對象時,再找IoC容器獲取. 
- DI: 即依賴注入, IoC容器需要為程序提供依賴對象,而所依賴的對象又依賴于其他對象,因此可以一次獲取該對象所依賴的所有對象(如Controller依賴于Service, Service依賴于DAO, 因此Controller找Ioc容器獲取Service, 當(dāng)IoC容器提供Service的同時,DAO也同時注入到Service中) 
 詳細可參考: IoC框架(依賴注入 DI)
Spring
- 方便解耦,簡化開發(fā) 
 Spring就是一個大工廠,可將所有對象創(chuàng)建和依賴關(guān)系的維護交給Spring管理;
- AOP支持 
 Spring支持面向切面編程,可以方便的實現(xiàn)對程序進行權(quán)限攔截/運行監(jiān)控/緩存實現(xiàn)等功能;
- 聲明式事務(wù)管理 
 只需通過配置就可完成對事務(wù)的管理,而無需手動編程;
- 方便程序的測試 
 Spring提供對Junit4支持,通過注解方便測試Spring程序;
- 集成各種優(yōu)秀框架 
 Spring不排斥各種優(yōu)秀的開源框架,其內(nèi)部提供了對各種優(yōu)秀框架(如:MyBatis/iBatis/Hibernate等)的直接支持;
- 降低JavaEE API的使用難度 
 Spring對JavaEE開發(fā)的一些API(如JDBC/JavaMail/遠程調(diào)用等)提供了封裝,大大降低API使用難度;
初識Spring
需求- 模擬用戶注冊過程:
- Spring依賴 
 進行Spring的IoC/DI開發(fā),只需要導(dǎo)入Spring最核心依賴:core/beans/context/expression,為了看到DEBUG信息,我們還可以加上commons-logging, 而junit, 則是做單元測試必備的:
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>4.2.0.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.2.0.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>4.2.0.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-expression</artifactId><version>4.2.0.RELEASE</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version></dependency>
</dependencies>- Controller
/*** Created by jifang on 15/12/5.*/
public class UserController {/*** 依賴注入(DI): 在Spring構(gòu)造UserController對象時, 可以同時將構(gòu)造好的UserService對象注入(下同)*/private IUserService userService;public IUserService getUserService() {return userService;}public void setUserService(IUserService userService) {this.userService = userService;}public void register(String userName, String password) {System.out.println("用戶: " + userName + " 進行注冊...");userService.register(userName, password);}
}- Service
public interface IUserService {void register(String userName, String password);
}public class UserServiceImpl implements IUserService {private IUserDao userDao;public IUserDao getUserDao() {return userDao;}public void setUserDao(IUserDao userDao) {this.userDao = userDao;}@Overridepublic void register(String userName, String password) {System.out.println("用戶: " + userName + " 進行注冊...");userDao.add(userName, passProcess(password));}// 對密碼進行加密處理private String passProcess(String password) {System.out.println("密碼: " + password + "加密處理...");return password;}
}- DAO
public interface IUserDao {void add(String userName, String password);
}public class UserDaoImpl implements IUserDao {@Overridepublic void add(String userName, String password) {System.out.println("用戶: " + userName + ", 密碼: " + password + " 加入數(shù)據(jù)庫");}
}- 配置Bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userDao" class="com.fq.first.dao.impl.UserDaoImpl"></bean><bean id="userService" class="com.fq.first.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property></bean><bean id="userController" class="com.fq.first.controller.UserController"><property name="userService" ref="userService"></property></bean></beans>- 測試
/*** Created by jifang on 15/12/5.*/
public class UserControllerTest extends TestCase {/*** 加載Spring容器*/private ApplicationContext context;@Beforepublic void setUp() throws Exception {context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");}@Testpublic void testRegister() throws Exception {UserController controller = context.getBean("userController", UserController.class);controller.register("翡青", "123");}
}- 在程序中通過ApplicationContext接口加載Spring容器, 獲取Spring工廠對象 - ClassPathXmlApplicationContext//讀取src下配置文件
- FileSystemXmlApplicationContext//讀取WEB-INF下配置文件
 
- Spring對象工廠- BeanFactory與ApplicationContext: - ApplicationContext是- BeanFactory的子接口,- BeanFactory是Spring最核心工廠接口。
- ApplicationContext提供更多功能(如國際化處理/自動裝配Bean/不同應(yīng)用層的Context實現(xiàn))
- ApplicationContext會在容器初始化時對其中管理Bean對象進行創(chuàng)建,- BeanFactory會在對象獲取時才進行初始化.
 
XML裝配
Spring提供了兩種裝配Bean的方式, XML與注解,其中XML方式Spring支持較早,現(xiàn)在在配置一些不是自己寫的Bean時(如數(shù)據(jù)庫連接池等從Jar包種引入的Bean)時是非常有用,而注解方式則常用于裝配自己寫的Bean.
三種實例化Bean的方式
- 構(gòu)造器實例化
<!--使用構(gòu)造器(默認無參)構(gòu)造對象-->
<bean id="constructBean" class="com.fq.instance.ConstructBean">
</bean>- 靜態(tài)工廠的靜態(tài)方法實例化
<!--使用靜態(tài)工廠構(gòu)造對象, 注: class應(yīng)為工廠類-->
<bean id="staticBean" class="com.fq.instance.StaticBeanFactory" factory-method="getInstance">
</bean>- 實例工廠的實例方法實例化
<!--使用實例工廠構(gòu)造對象, 注: 要先實例化工廠-->
<bean id="beanFactory" class="com.fq.instance.InstanceBeanFactory">
</bean>
<!-- 再通過工廠對象的實例方法,構(gòu)造目標(biāo)對象 -->
<bean id="instanceBean" factory-bean="beanFactory" factory-method="getInstance">
</bean>Bean作用域
| 類別 | 說明 | 
|---|---|
| singleton | 在容器中僅存在一個實例(單例模式) | 
| prototype | 每次從容器中獲取都返回一個新的實例,即每次調(diào)用getBean()時,都執(zhí)行一次構(gòu)造方法(lazy,原型模式) | 
| request | 每次HTTP請求都會創(chuàng)建一個新的Bean,該作用域僅適用于 WebApplicationContext環(huán)境(不常用) | 
| session | 同一個 Session共享一個Bean,僅適用于WebApplicationContext環(huán)境(不常用) | 
| globalSession | 一般用于Porlet應(yīng)用環(huán)境,該作用域僅適用于 WebApplicationContext環(huán)境(不常用) | 
- scope
<!--Spring使用scope標(biāo)簽來制定bean的作用域(默認為Singleton)-->
<bean id="singletonBean" class="com.fq.instance.SingletonBean" scope="singleton">
</bean>
<bean id="prototypeBean" class="com.fq.instance.PrototypeBean" scope="prototype">
</bean>Bean生命周期
Spring初始化/銷毀bean時, 有時需要作一些處理工作, 因此Spring可以在創(chuàng)建和銷毀bean的時候調(diào)用bean的兩個生命周期方法;
/*** Created by jifang on 15/12/6.*/
public class LifecycleBean {public LifecycleBean() {System.out.println("Constructor ...");}/*** 聲明周期方法需: 無參, 無返回值, 非static*/public void setUp() {System.out.println("SetUp ...");}/*** 同上*/public void tearDown() {System.out.println("TearDown ...");}
}- 配置:
<!-- init-method屬性配置初始化方法,destroy-method屬性配置銷毀方法-->
<bean id="lifecycleBean" class="com.fq.bean.LifecycleBean" init-method="setUp" destroy-method="tearDown">
</bean>- 測試
/*** Created by jifang on 15/12/6.*/
public class LifecycleBeanTest extends TestCase {private ClassPathXmlApplicationContext context;@Beforepublic void setUp() throws Exception {context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");}@Testpublic void testLifecycle(){LifecycleBean bean = context.getBean("lifecycleBean", LifecycleBean.class);System.out.println(bean);}@Afterpublic void tearDown() throws Exception {// 必須手動調(diào)用context的close方法, 才會執(zhí)行bean的銷毀方法context.close();}
}初始化方法與構(gòu)造方法的區(qū)別?
1) 構(gòu)造方法為對象申請空間, 完成對象基本屬性的初始化;
2) 初始化方法主要完成對象復(fù)雜構(gòu)造過程;
3) Java建議將對象復(fù)雜構(gòu)造過程單獨抽取出初始化方法, 如javax.servlet.GenericServlet
的init方法
public void init(ServletConfig config) throws ServletException {this.config = config;this.init();
}后處理器
Spring提供了BeanPostProcessor接口,在構(gòu)造Bean對象執(zhí)行對象初始化(init-method)方法時可以對Bean進行處理;
/*** Created by jifang on 15/12/6.*/
public class PrintBeanProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 可以根據(jù)beanName來決定對那個Bean進行后處理操作if (beanName.equals("lifecycleBean")) {System.out.println("后處理bean -- process before ...");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {// 如果不制定beanName, 則默認處理所有BeanSystem.out.println("后處理bean -- process after ...");return bean;}
}- 配置
<!-- 為Spring容器所用的bean, 不需配置id -->
<bean class="com.fq.processor.PrintBeanProcessor"></bean>這樣在執(zhí)行init-method[setUp]的前后, 會分別執(zhí)行BeanPostProcessor中的兩個方法.
后處理器可以在對象構(gòu)造過程中提供代理,這是AOP自動代理的核心.
XML依賴注入
Spring配置文件支持構(gòu)造參數(shù)屬性注入和Setter方法屬性注入;
1. 構(gòu)造參數(shù)注入
<bean id="bean" class="com.fq.di.Bean"><!--index   代表參數(shù)順序(從0開始)name    代表參數(shù)名type    參數(shù)類型value   注入的參數(shù)值ref     引用另一個bean元素的id--><constructor-arg index="0" type="java.lang.String" value="fei_qing"></constructor-arg><constructor-arg index="1" type="java.lang.Double" value="3.14"></constructor-arg>
</bean>2. Setter方法注入
<bean id="bean" class="com.fq.di.Bean"><!--name    屬性名(congSetter方法獲得)value   注入的參數(shù)值ref     引用的另一個bean的id--><property name="name" value="fei_qing"></property><property name="price" value="88.8"></property>
</bean>3. p名稱空間注入
P名稱空間在spring2.5版本后引入, 目的是為了簡化屬性依賴注入(setter方法)
<!--p:屬性名="XXX", 引入常量值p:屬性名-ref="XXX", 引用其他Bean對象
-->
<bean id="bean" class="com.fq.di.Bean" p:name="feiqing" p:price="1188">
</bean>4. SpEL表達式
在spring3.0之后,引入SpEL表達式,以簡化屬性注入.
#{表達式}, 通過value屬性注入: 可以引用一個Bean對象/對象屬性/對象方法… 詳細可參考Spring 表達式語言(SpEL)
- Bean
public class Car {private String logo;private double price;private String owner;public String getLogo() {return logo;}public void setLogo(String logo) {this.logo = logo;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public String getOwner() {return owner;}public void setOwner(String owner) {this.owner = owner;}
}public class Employ {private String name;private Car car;public String getName() {return name;}public void setName(String name) {this.name = name;}public Car getCar() {return car;}public void setCar(Car car) {this.car = car;}
}- 配置
<!--SpEL 使用#{}來引用/獲取對象-->
<bean id="car" class="com.fq.di.Car"><property name="logo" value="#{'logo.pic'}"/><property name="price" value="#{18.8}"/><property name="owner" value="#{'feiqing'}"/>
</bean><bean id="employ" class="com.fq.di.Employ"><!-- 可以直接使用value來引用到對象, 而不是ref --><property name="car" value="#{car}"/><!-- 可以直接引用一個對象的屬性 --><!--<property name="name" value="#{car.owner}"/>--><!-- 還可以直接調(diào)用對象的方法 --><property name="name" value="#{car.getOwner().toUpperCase()}"/>
</bean>4. 集合屬性注入
java常見集合: List/Set/Map/Properties等, Spring為每種集合都提供一個標(biāo)簽進行注入;
- Bean
public class CollectionBean {private List<String> list;private Set<String> set;private Map<String, String> map;private Properties properties;public List<String> getList() {return list;}public void setList(List<String> list) {this.list = list;}public Set<String> getSet() {return set;}public void setSet(Set<String> set) {this.set = set;}public Map<String, String> getMap() {return map;}public void setMap(Map<String, String> map) {this.map = map;}public Properties getProperties() {return properties;}public void setProperties(Properties properties) {this.properties = properties;}
}- 配置
<bean id="collectionBean" class="com.fq.di.CollectionBean"><property name="list"><list><value>aa</value><value>bb</value><value>cc</value><value>dd</value></list></property><property name="set"><set><value>11</value><value>12</value><value>11</value></set></property><property name="map"><map><entry key="key1" value="value1"/><entry key="key2" value="value2"/></map></property><property name="properties"><props><prop key="key1">value_1</prop><prop key="key2">value_2</prop></props></property>
</bean>注解裝配
注解配置Bean
- 在需要Spring管理的類上添加@Component注解
 (@Component還可以指定組件名@Component(value = "xxx"))
@Component
public class Bean {private String name;private Double price;public Bean() {}public Bean(String name, Double price) {this.name = name;this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Double getPrice() {return price;}public void setPrice(Double price) {this.price = price;}
}- 引入context命名空間并批量掃描
<?xml version="1.0" encoding="UTF-8"?>
<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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.fq.di"/>
</beans>Spring細化@Component以細分組件功能,提供了以下三個等價注解:
| 注解 | 說明 | 
|---|---|
| @Controller | 控制器,web層組件 | 
| @Service | 業(yè)務(wù)類,業(yè)務(wù)層組件 | 
| @Repository | 持久層組件 | 
Bean作用域
通過@Scope注解指定作用域
@Component
@Scope("prototype")
public class Bean {// ...
}Bean生命周期
| @PostConstruct | 初始化 | 
|---|---|
| @PreDestroy | 銷毀 | 
- Bean
public class Bean {@PostConstructpublic void setUp(){System.out.println("setUp ...");}@PreDestroypublic void tearDown(){System.out.println("tearDown ...");}
}注解依賴注入
1. @Value
 - 簡單類型
@Component
public class Bean {@Value("feiqing")private String name;@Value("88.88")private Double price;// ....
}- 復(fù)雜屬性(使用SpEL表達式)
@Component
public class Bean {@Value("#{car}")private Car car;// ...
}2. @Autowired
 - @Autowired默認按照類型進行注入(如果容器中存在兩個相同類型對象,則- @Autowired無法注入)
@Component
public class Bean {@Autowiredprivate Car car;// ....
}- @Autowired+- @Qualifier指定注入Bean的id
@Component
public class Bean {@Autowired@Qualifier("car")private Car car;// ...
}3. @Resource
 Spring支持JSR-250規(guī)范,可以使用@Resource()進行屬性注入,功能和@Autowired相同:
@Controller(value = "bean")
public class Bean {@Resource(name = "car")private Car car;//...
}注解/XML混合
Bean定義使用XML,Bean關(guān)系依賴注入使用注解:
需要在applicationContext.xml中配置:
<context:annotation-config/>該配置可以使@Resource、@PostConstruct、@PreDestroy、@Autowired注解生效.
如果在配置文件中使用了
<context:component-scan base-package="xxx.xx"/>則具有了<context:annotation-config/>的效果, 不必再單獨配置.
轉(zhuǎn)載于:https://www.cnblogs.com/itrena/p/5926901.html
總結(jié)
以上是生活随笔為你收集整理的Spring 实践 -IoC的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: “男儿老富贵”下一句是什么
- 下一篇: 求一个带闫的好听的微信网名
