- 從大小、開銷兩方面而言荠瘪,Spring 都是輕量級(jí)的夯巷;
- 通過控制反轉(zhuǎn)技術(shù)(IOC)達(dá)到松耦合;
- 通過面向切面編程(AOP)實(shí)現(xiàn)業(yè)務(wù)邏輯和系統(tǒng)級(jí)服務(wù)的分離哀墓;
- 作為容器包含和管理應(yīng)用對(duì)象的配置和生命周期趁餐;
- 將簡單的組件配置組合成復(fù)雜的應(yīng)用。
官網(wǎng)
框架
- 半成品篮绰,定制規(guī)范后雷;
- 封裝了特定的處理流程和控制邏輯,是高內(nèi)聚的(而類庫是松散的工具組合)吠各;
- 提高代碼重用度臀突、開發(fā)效率和質(zhì)量,易于上手贾漏、快速解決問題候学。
控制反轉(zhuǎn)(IOC)
- 控制反轉(zhuǎn)即獲得依賴對(duì)象的過程被反轉(zhuǎn);控制權(quán)的轉(zhuǎn)移纵散,應(yīng)用程序本身不負(fù)責(zé)對(duì)象的創(chuàng)建和維護(hù)梳码,而是由外部容器負(fù)責(zé)創(chuàng)建和維護(hù)隐圾;
- 依賴注入:IOC 的一種實(shí)現(xiàn),創(chuàng)建對(duì)象并組裝對(duì)象之間的關(guān)系掰茶,由 IOC 容器(中介)在運(yùn)行期間動(dòng)態(tài)地將某種依賴關(guān)系注入到對(duì)象中并返回暇藏。
面向接口編程
- 接口:用于溝通的中介物的抽象化(提供功能方法的聲明);
- 面向接口編程
- 系統(tǒng)設(shè)計(jì)中濒蒋,分清層次和調(diào)用關(guān)系叨咖,每層只向上層提供功能接口,層間僅依賴接口而非實(shí)現(xiàn)類啊胶;
- 接口實(shí)現(xiàn)的變動(dòng)不影響各層間的調(diào)用(在公共服務(wù)中尤其重要)。
接口與實(shí)現(xiàn)類的使用
public interface OneInterface {
public void say(String arg);
}
public class OneInterfaceImpl implements OneInterface {
public void say(String arg) {
System.out.println("ServiceImpl say: " + arg);
}
}
依賴注入的實(shí)現(xiàn)
- 基于注解
- 基于 XML 配置文件
配置文件 spring-ioc.xml
<?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="oneInterface" class="com.imooc.ioc.interfaces.OneInterfaceImpl"></bean>
</beans>
測試基類:用于對(duì) Spring 配置文件的加載垛贤、銷毀
public class UnitTestBase {
private ClassPathXmlApplicationContext context;
private String springXmlpath;
public UnitTestBase() {}
public UnitTestBase(String springXmlpath) {
this.springXmlpath = springXmlpath;
}
@Before
public void before() {
if (StringUtils.isEmpty(springXmlpath)) {
springXmlpath = "classpath*:spring-*.xml";
}
try {
context = new ClassPathXmlApplicationContext(springXmlpath.split("[,\\s]+"));
context.start();
} catch (BeansException e) {
e.printStackTrace();
}
}
@After
public void after() {
context.destroy();
}
@SuppressWarnings("unchecked")
protected <T extends Object> T getBean(String beanId) {
try {
return (T) context.getBean(beanId);
} catch (BeansException e) {
e.printStackTrace();
return null;
}
}
protected <T extends Object> T getBean(Class<T> clazz) {
try {
return context.getBean(clazz);
} catch (BeansException e) {
e.printStackTrace();
return null;
}
}
}
注入測試
@RunWith(BlockJUnit4ClassRunner.class)
public class TestOneInterface extends UnitTestBase {
public TestOneInterface() {
super("classpath*:spring-ioc.xml");
}
@Test
public void testSay() {
OneInterface oneInterface = super.getBean("oneInterface");
oneInterface.say("This is a test.");
}
}
Spring 注入方式
- 啟動(dòng) Spring 容器加載 Bean 配置的時(shí)候焰坪,完成對(duì)變量的賦值行為;
- 常用的注入方式:設(shè)值注入(自動(dòng)調(diào)用 Setter 方法對(duì)屬性賦值)聘惦、構(gòu)造注入(通過構(gòu)造器傳入 bean)某饰。
<!-- Service 層設(shè)值注入 -->
<bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">
<property name="injectionDAO" ref="injectionDAO"></property>
</bean>
<!-- Service 層構(gòu)造注入 -->
<bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">
<constructor-arg name="injectionDAO" ref="injectionDAO"></constructor-arg> <!-- 在構(gòu)造方法中傳入 injectionDAO,注意參數(shù)名稱必須一致 -->
</bean>
<!-- DAO 層 -->
<bean id="injectionDAO" class="com.imooc.ioc.injection.dao.InjectionDAOImpl"></bean> <!-- 作為 injectionService 對(duì)象的成員變量 -->
Bean 裝配(基于 XML 配置文件)
配置項(xiàng)
Spring IOC Bean 容器中常用到以下配置項(xiàng)善绎,其中 class 是必須的:
- id
- class
- scope
- constructor arguments
- properties
- autowiring mode
- lazy-initialization mode
- initializa/destruction method
作用域
- singleton:Bean 容器中(
context = new ClassPathXmlApplicationContext(xxx)
)唯一(注意對(duì)一個(gè)類進(jìn)行單元測試時(shí)每個(gè)方法都是不同的 IOC 容器)黔漂; - prototype:每次請(qǐng)求(使用)創(chuàng)建新的實(shí)例,由 destroy 銷毀禀酱;
- request:每次 http 請(qǐng)求創(chuàng)建要給實(shí)例且僅在當(dāng)前 request 中生效炬守;
- session:每次 http 請(qǐng)求創(chuàng)建,當(dāng)前 Session 內(nèi)有效剂跟;
- global session:常用于多系統(tǒng)集成减途,基于 portlet 的 web 中有效(portlet 定義了 global session),如果是在 Web 中則與 session 相同曹洽。
生命周期
- 定義:在 XML 配置文件中定義(見前面)
- 初始化 :實(shí)現(xiàn)
org.springframework.beans.factory.InitializingBean
接口鳍置,并覆蓋afterPropertiesSet
方法;或配置init-method
送淆; - 使用 税产;
- 銷毀:與初始化類似,實(shí)現(xiàn)
org.springframework.beans.factory.DisposableBean
接口偷崩,并覆蓋destroy
方法屡拨,用于釋放連接池等清理操作僚害。
配置全局默認(rèn)初始化、銷毀方法(自己配置的 init-method 和 destroy-method 會(huì)覆蓋)
<?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"
default-init-method="defautInit" default-destroy-method="defaultDestroy">
<bean id="beanLifeCycle" class="com.imooc.lifecycle.BeanLifeCycle" init-method="start" destroy-method="stop"></bean>
</beans>
public class BeanLifeCycle implements InitializingBean, DisposableBean {
public void defautInit() {
System.out.println("Bean defautInit.");
}
public void defaultDestroy() {
System.out.println("Bean defaultDestroy.");
}
@Override
public void destroy() throws Exception {
System.out.println("Bean destroy.");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Bean afterPropertiesSet.");
}
public void start() {
System.out.println("Bean start .");
}
public void stop() {
System.out.println("Bean stop.");
}
}
Aware
- Spring 中提供以 Aware 結(jié)尾的接口,可用于獲取相應(yīng)的資源卖宠、執(zhí)行一定操作;
- 為對(duì) Spring 進(jìn)行簡單的擴(kuò)展提供了方便的入口抡锈。
常用接口:
- MessageSourceAware
- NotificationPublisherAware
- PortletConfitAware
- PortletContextAware
- ResourceLoaderAware
- ServletConfigAware
- ServletContextAware
實(shí)現(xiàn) BeanNameAware
接口
public class MoocBeanName implements BeanNameAware, ApplicationContextAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("MoocBeanName : " + name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("setApplicationContext : " + applicationContext.getBean(this.beanName).hashCode());
}
}
測試
@Test
public void textMoocBeanName() {
System.out.println("textMoocBeanName : " + super.getBean("moocBeanName").hashCode());
}
自動(dòng)裝配
- 前面講到 Spring 的注入時(shí)設(shè)置注入和構(gòu)造注入都需要在 XML 配置文件怜珍、
<bean>
配置項(xiàng)中聲明渡紫; -
使用自動(dòng)裝配,可以根據(jù) Bean 的名稱考赛、類型惕澎、構(gòu)造器等自動(dòng)解決依賴關(guān)系,有以下實(shí)現(xiàn)方式:
spring-autowiring.xml
<?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"
default-autowire="constructor">
<bean id="autoWiringService" class="com.imooc.autowiring.AutoWiringService" ></bean>
<bean class="com.imooc.autowiring.AutoWiringDAO" ></bean>
</beans>
AutoWiringDAO.java
public class AutoWiringDAO {
public void say(String word) {
System.out.println("AutoWiringDAO : " + word);
}
}
AutoWiringService.java
public class AutoWiringService {
private AutoWiringDAO autoWiringDAO;
public AutoWiringService(AutoWiringDAO autoWiringDAO) {
System.out.println("AutoWiringService");
this.autoWiringDAO = autoWiringDAO;
}
public void setAutoWiringDAO(AutoWiringDAO autoWiringDAO) {
System.out.println("setAutoWiringDAO");
this.autoWiringDAO = autoWiringDAO;
}
public void say(String word) {
this.autoWiringDAO.say(word);
}
}
TestAutoWiring.java
@RunWith(BlockJUnit4ClassRunner.class)
public class TestAutoWiring extends UnitTestBase {
public TestAutoWiring() {
super("classpath:spring-autowiring.xml");
}
@Test
public void testSay() {
AutoWiringService service = super.getBean("autoWiringService");
service.say(" this is a test");
}
}
Resources
針對(duì)于資源文件的統(tǒng)一接口
public class MoocResource implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
public void resource() throws IOException {
Resource resource = applicationContext.getResource("config.txt");
System.out.println(resource.getFilename());
System.out.println(resource.contentLength());
}
}
@RunWith(BlockJUnit4ClassRunner.class)
public class TestResource extends UnitTestBase {
public TestResource() {
super("classpath:spring-resource.xml");
}
@Test
public void testResource() {
MoocResource resource = super.getBean("moocResource");
try {
resource.resource();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Bean 裝配(基于注解)
spring-beanannotation.xml
<?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.imooc.beanannotation"></context:component-scan>
</beans>
BeanAnnotation.java
@Scope
@Component
public class BeanAnnotation {
public void say(String arg) {
System.out.println("BeanAnnotation : " + arg);
}
public void myHashCode() {
System.out.println("BeanAnnotation : " + this.hashCode());
}
}
測試
@RunWith(BlockJUnit4ClassRunner.class)
public class TestBeanAnnotation extends UnitTestBase {
public TestBeanAnnotation() {
super("classpath*:spring-beanannotation.xml");
}
@Test
public void testSay() {
BeanAnnotation bean = super.getBean("beanAnnotation");
bean.say("This is test.");
bean = super.getBean("bean");
bean.say("This is test.");
}
@Test
public void testScpoe() {
BeanAnnotation bean = super.getBean("beanAnnotation");
bean.myHashCode();
bean = super.getBean("beanAnnotation");
bean.myHashCode();
}
}
Bean 的定義
其中注解中的參數(shù)表示 Bean 在容器中的 Id颜骤,默認(rèn)為類名(首字母改為小寫)唧喉。
Classpath 掃描與組件管理:@Component
、@Repository
忍抽、@Service
八孝、@Controller
元注解:@Target
、@Retention
鸠项、@Documented
類的自動(dòng)檢測及 Bean 的注冊(cè)
使用 component-scan 可以掃描加上了
@Component
注解(及其子注解)的類干跛,在 base-package 上配置需要掃描的包,包括了 annotation-config 的功能祟绊。
使用過濾器進(jìn)行自定義掃描
作用域:@Scope
代理方式
常用注解說明
@Required
@Autowired
public interface InjectionService {
public void save(String arg);
}
@Service
public class InjectionServiceImpl implements InjectionService {
// @Autowired
private InjectionDAO injectionDAO;
@Autowired
public InjectionServiceImpl(InjectionDAO injectionDAO) {
this.injectionDAO = injectionDAO;
}
// @Autowired
public void setInjectionDAO(InjectionDAO injectionDAO) {
this.injectionDAO = injectionDAO;
}
public void save(String arg) {
System.out.println("Service接收參數(shù):" + arg);
arg = arg + ":" + this.hashCode();
injectionDAO.save(arg);
}
}
@RunWith(BlockJUnit4ClassRunner.class)
public class TestInjection extends UnitTestBase {
public TestInjection() {
super("classpath:spring-injection.xml");
}
@Test
public void testSetter() {
InjectionService service = super.getBean("injectionService");
service.save("這是要保存的數(shù)據(jù)");
}
@Test
public void testCons() {
InjectionService service = super.getBean("injectionService");
service.save("這是要保存的數(shù)據(jù)");
}
}
public interface BeanInterface {}
@Order(2)
@Component
public class BeanImplOne implements BeanInterface {}
@Order(1)
@Component
public class BeanImplTwo implements BeanInterface {}
@Component
public class BeanInvoker {
@Autowired
private List<BeanInterface> list;
@Autowired
private Map<String, BeanInterface> map;
@Autowired
@Qualifier("beanImplTwo")
private BeanInterface beanInterface;
public void say() {
if (null != list && 0 != list.size()) {
System.out.println("list...");
for (BeanInterface bean : list) {
System.out.println(bean.getClass().getName());
}
} else {
System.out.println("List<BeanInterface> list is null !!!!!!!!!!");
}
System.out.println();
if (null != map && 0 != map.size()) {
System.out.println("map...");
for (Map.Entry<String, BeanInterface> entry : map.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue().getClass().getName());
}
} else {
System.out.println("Map<String, BeanInterface> map is null !!!!!!!!!!");
}
System.out.println();
if (null != beanInterface) {
System.out.println(beanInterface.getClass().getName());
} else {
System.out.println("beanInterface is null...");
}
}
}
@Qualifier
@Bean - 基于 Java 容器的注解
使用 @Bean
注解楼入,Bean 的名稱默認(rèn)是方法的名稱。
@Configuration
@ImportResource("classpath:config.xml")
public class StoreConfig {
// @Value("${url}")
// private String url;
//
// @Value("${jdbc.username}")
// private String username;
//
// @Value("${password}")
// private String password;
//
// @Bean
// public MyDriverManager myDriverManager() {
// return new MyDriverManager(url, username, password);
// }
// @Bean(name = "stringStore", initMethod="init", destroyMethod="destroy")
// public Store stringStore() {
// return new StringStore();
// }
// @Bean(name = "stringStore")
// @Scope(value="prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
// public Store stringStore() {
// return new StringStore();
// }
@Autowired
private Store<String> s1;
@Autowired
private Store<Integer> s2;
@Bean
public StringStore stringStore() {
return new StringStore();
}
@Bean
public IntegerStore integerStore() {
return new IntegerStore();
}
// @Bean(name = "stringStoreTest")
// public Store stringStoreTest() {
// System.out.println("s1 : " + s1.getClass().getName());
// System.out.println("s2 : " + s2.getClass().getName());
// return new StringStore();
// }
}
public class StringStore implements Store<String> {
public void init() {
System.out.println("This is init.");
}
public void destroy() {
System.out.println("This is destroy.");
}
}
@RunWith(BlockJUnit4ClassRunner.class)
public class TestJavabased extends UnitTestBase {
public TestJavabased() {
super("classpath*:spring-beanannotation.xml");
}
@Test
public void test() {
Store store = super.getBean("stringStore");
System.out.println(store.getClass().getName());
}
@Test
public void testMyDriverManager() {
MyDriverManager manager = super.getBean("myDriverManager");
System.out.println(manager.getClass().getName());
}
@Test
public void testScope() {
Store store = super.getBean("stringStore");
System.out.println(store.hashCode());
store = super.getBean("stringStore");
System.out.println(store.hashCode());
}
@Test
public void testG() {
StringStore store = super.getBean("stringStoreTest");
}
}
面向切面編程
面向切面編程(AOP)是分離應(yīng)用的業(yè)務(wù)邏輯和系統(tǒng)級(jí)服務(wù)進(jìn)行內(nèi)聚性的開發(fā)牧抽。