spring是輕量級的(非侵入式,這意味着你寫的邏輯代碼無需依賴框架本身,不用繼承spring中的父類等)。Spring框架主要提供了IoC容器、AOP、數據訪問、Web開發、消息、測試等相關技術。本文主要介紹Spring中的一些小知識點,關於模塊功能竟會在后期整理。
Spring的模塊
Spring是模塊化的,可以只使用需要的部分,而無需引入整個框架。Spring模塊包括IoC容器、AOP、數據訪問、Web開發、消息、測試等。
Spring的具體結構如下圖:
Spring的每一個小單元都至少對應一個jar包。
-
核心容器(Core Container)
-
Spring-Core : 核心工具類
-
Spring-Beans:定義Bean的支持
-
Spring-Context:運行時容器 、 Spring-Contex-Support : 對第三方包的繼承支持
-
Spring-Expression:使用表達式語言在運行時查找和操作對象
-
切面(AOP、Aspects)
-
Spring-AOP:基於代理的AOP支持
-
Spring-Aspects:基於AspectJ的AOP支持
-
消息(Messaging)
-
Spring-Messaging:對於消息架構和協議的支持
-
網絡(Web)
-
Spring-Web: 提供基礎的Web功能,在Web項目中提供Spring容器
-
Spring-Webmvc:提供基於servlet的Spring MVC
-
Spring-WebSocket:提供WebSocket功能
-
Spring-WebSocket-Portlet:提供Portlet環境支持
-
數據訪問\集成(Data Access\Integration)
-
Spring-JDBC:提供JDBC訪問數據庫的支持
-
Spring-TX:提供編程式和聲明式的事務支持
-
Spring-ORM:提供對對象\關系映射的支持
-
Spring-OXM:提供對象\xml映射的支持
-
Spring-JMS:提供對JMS的支持
Spring框架的四大原則:
-
使用POJO(普通的Java對象)進行輕量級和最小侵入式開發
-
通過依賴注入和基於接口編程實現松耦合
-
通過AOP和默認習慣進行聲明式編程
-
使用AOP和模板(templet)減少模式化代碼
Spring事件(Application Event)
通過發布者,將事件發布,監聽器會監聽發布的事件並接受發送的信息。
Spring事件為Bean之間的消息通信提供了支持。(當一個Bean處理完一個任務之后,希望另一個Bean知道並能做相應的處理,這時需要讓另一個Bean監聽當前Bean所發送的事件。
具體實現:
1.自定義事件,繼承ApplicationEvent
public class MyEvent extends ApplicationEvent{ private static final long serialVersionUID = 3280614981975983900L; private String msg; public MyEvent(Object source, String msg) { super(source); this.setMsg(msg); } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
2.自定義監聽器,實現ApplicationListener
@Component public class MyListener implements ApplicationListener<MyEvent>{ @Override public void onApplicationEvent(MyEvent event) { String msg = event.getMsg(); System.out.println(">>>>>>>>>>>>>>>>Get Message is :"+msg); } }
3.使用容器發布事件
@Component public class MyPublisher { @Autowired ApplicationContext context; public void publish(String msg){ context.publishEvent(new MyEvent(this, msg)); } }
4.Demo
public class EventDemo { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(EventConfig.class); MyPublisher publisher = context.getBean(MyPublisher.class); publisher.publish(">>>>>>>>>>>>>>>>>>>>Hello Appolication Event!"); context.close(); } }
Spring Aware
Spring依賴注入的最大亮點就是Bean對Spring容器的存在是無意識的(即:你可以將容器替換成別的容器)。但是實際項目中,你不可避免的要用到Spring容器本身的功能資源,此時Bean必須意識到Spring容器的存在,這就是Spring Aware。
Spring Aware的主要目的是讓Bean獲取Spring容器的服務。
下表是Aware接口及介紹:
具體實現:
1.創建Service,實現需要的Aware接口
@Service public class AwareService implements BeanNameAware,ResourceLoaderAware{ private String beanName; private ResourceLoader loader; @Override public void setBeanName(String name) { this.beanName = name; } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.loader = resourceLoader; } public void print() throws IOException{ //Log: >>>>>>>>>>>>>>>>>>>>>>Bean name is : awareService System.out.println(">>>>>>>>>>>>>>>>>>>>>>Bean name is : "+this.beanName); Resource resource = loader.getResource("classpath:com/blueStarWei4Spring/Aware/aware.txt"); //Log:>>>>>>>>>>>>>>>>>>>>>>Resource context is : Spring Aware Test. // Please continue... System.out.println(">>>>>>>>>>>>>>>>>>>>>>Resource context is : "+IOUtils.toString(resource.getInputStream())); } }
2.創建外部資源aware.txt【為了實現ResourceLoaderAware讀取資源文件】
Spring Aware Test. Please continue...
3.Demo
public class AwareDemo { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AwareConfig.class); try { AwareService service = context.getBean(AwareService.class); service.print(); } catch (IOException e) { e.printStackTrace(); } context.close(); } }
多線程(異步任務)
Spring通過任務執行器(TaskExecutor)來實現多線程和並發編程。
使用ThreadPoolTaskExecutor可實現一個基於線程池的TaskExecutor,在配置類中通過@EnableAsync開啟對異步任務的支持,並通過在Bean的方法上使用@Async來聲明其是一個異步任務。
具體實現:
1.創建配置類,實現AsyncConfigurer接口
@Configuration @ComponentScan("com.blueStarWei4Spring.Thread") @EnableAsync public class TaskExecutorConfig implements AsyncConfigurer{ @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(5); taskExecutor.setMaxPoolSize(10); taskExecutor.setQueueCapacity(25); taskExecutor.initialize(); return taskExecutor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return null; } }
2.創建service
@Service public class AsyncTaskService { @Async public void executeAsyncTask(int i){ System.out.println("Execute Async Task : "+i); }
}
3.Demo
public class BeanDemo { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TaskExecutorConfig.class); AsyncTaskService service = context.getBean(AsyncTaskService.class); for (int i = 0; i < 10; i++) { //Execution is non-order service.executeAsyncTask(i); } context.close(); } }
計划任務
有時需要按照計划在指定的事件執行任務,或者每隔一段時間執行一次任務,這時候就需要計划任務(又稱為:定時任務)。
Spring提供了@EnableSchedualing開啟對計划任務的支持,並通過@Scheduled聲明計划任務
具體實現:
1.在配置類上使用@EnableSchedualing開啟對計划任務的支持
@Configuration @ComponentScan("com.blueStarWei4Spring.Schedule") @EnableScheduling public class ScheduledTaskConfig { }
2.在要執行計划任務的方法上使用@Scheduled聲明計划任務
@Service public class ScheduledTaskService { //fixedRate = 5000 :每隔5秒執行一次 @Scheduled(fixedRate = 5000) public void reportCurrentTime(){ System.out.println(">>reportCurrentTime>>>>>>>>>>>Current Time is :"+LocalTime.now()); } //cron表達式: 秒 分 時 日 月 年 //cron="0 06 19 * * ?" : 每天的19:06執行 @Scheduled(cron="0 06 19 * * ?") public void fixTimeExecute(){ System.out.println(">>>>fixTimeExecute>>>>>>>>>>>>>>>>Current Time is :"+LocalTime.now()); } }
3.Demo
只需要加載配置類,不需要手動調用計划任務。
public class ScheduledTaskDemo { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScheduledTaskConfig.class); } }
4.補充
public class LinuxCondition implements Condition{ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //TODO you can add your logic return true; } }
public class WindowsCondition implements Condition{ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //TODO you can add your logic return false; } }
2.創建Service:根據產生的Bean處理業務
public interface ListService { public String showListCmd(); }
public class LinuxListService implements ListService { @Override public String showListCmd() { return "ls"; } }
public class WindowsListService implements ListService { @Override public String showListCmd() { return "dir"; } }
3.在配置類中配置Service
@Configuration public class ConditionConfig { @Bean @Conditional(WindowsCondition.class) public ListService windowsListService(){ return new WindowsListService(); } @Bean @Conditional(LinuxCondition.class) public ListService linuxListService(){ return new LinuxListService(); } }
4.Demo
public class ConditionDemo { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionConfig.class); ListService service = context.getBean(ListService.class); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>"+service.showListCmd()); } }
補充概念
元數據:描述數據的數據,本身不具備任何操作。(比如:注解、xml配置)
元注解和組合注解:可以注解到別的注解上的注解叫元注解,被注解的注解叫做組合注解
Spring注解集合
Spring注解
|
|||
類型
|
注解
|
用途
|
備注
|
聲明Bean
|
@Component
|
組件,表明這個類是一個Bean
|
通常用於實體類
|
@Service
|
在業務邏輯層使用(Service層)
|
|
|
@Repository
|
在數據訪問層使用(DAO層)
|
|
|
@Controller
|
在展示層使用,控制器的聲明
|
|
|
注入Bean
|
@Autowired
|
注解在屬性或set()上
【推薦注解在屬性上】
|
按byType自動注入
可以與@Qualifier(name)聯合使用,指定按byNAme自動注入
|
@Resource
|
按ByName自動注入
|
||
@Inject
|
由JSR-250提供
|
||
配置類
|
@Configuration
|
聲明當前類為配置類
|
相當於xml形式的Spring配置
|
@Bean
|
聲明方法的返回值是一個Bean(方法上)
|
|
|
@ComponentScan
|
用於對Component進行掃描並注冊成Bean
|
|
|
@EnableWebMvc
|
開啟web MVC的配置支持
|
|
|
@EnableConfigrationProperties
|
開啟對@ConfigurationProperties注解配置Bean的支持
|
|
|
@EnableJpaRepositories
|
開啟對Spring Data JPA Repository的支持
|
|
|
@EnableTransactionManagement
|
開啟注解式事務的支持
|
|
|
@EnableCaching
|
開啟注解式緩存的支持
|
|
|
@EnableAspectJAutoProxy
|
開啟Spring對AspectJ代理的支持
|
|
|
AOP
|
@Aspect
|
聲明一個切面(類上)
|
|
@Order
|
指定切面的優先級
|
可缺省
|
|
@PointCut
|
聲明切點
|
在Java配置類中使用
|
|
@Before
|
在方法執行之前執行(方法上)
|
|
|
@After
|
在方法執行之后執行(方法上)
|
被代理的方法拋出異常,@After標記的方法也會執行
|
|
@AfterReturning
|
在方法正常執行之后執行(方法上)
|
被代理的方法拋出異常,@AfterReturning標記的方法不會執行
|
|
@AfterThrowing
|
在方法拋出異常后執行
|
|
|
@Around
|
在方法執行之前以及之后執行(方法上)
|
可以修改被代理方法的返回值
|
|
@Bean的屬性支持
|
@Scope
|
設置如何創建Bean實例
|
設置類型包括:
Singleton:單例(默認模式)
Protetype:每次調用創建一個新的bean
Request:給每個Http request創建一個bean
Session:給每個Http session創建一個bean
GlobalSession:給每個global Http session創建一個bean
|
@StepSession
|
在Spring Batch中還有涉及
|
|
|
@PostConstruct
|
在構造函數執行之后執行(方法上)
|
由JSR-250提供,等價於xml配置文件中bean的initMethod
|
|
@PreDestroy
|
在bean銷毀前執行
|
由JSR-250提供,等價於xml配置文件中bean的destroyMethod
|
|
@Value注解
|
@Value
[使用的是SpEL表達式]
|
注入普通字符
|
@Value("Winn")
String name;
|
注入操作系統屬性
|
@Value("#{systemProperties['os.name']}")
String osName;
|
||
注入表達式結果
|
@Value("#{T(java.lang.Math).random()*100}")
String randomNumber;
|
||
注入其他bean屬性的值
|
@Value("#{domeClass.name}")
String name;
|
||
注入文件資源
|
@Value("classpath:com/blueStarWei/rsc/test.txt")
Resource file;
|
||
注入外部配置文件
|
@Value("${book.name}")
String bookName;
還需要在類上添加
@PropertySource("classpath:com/blueStarWei/rsc/test.txt")
還需要配置一個PropertySourcesPlaceholderConfigurer的bean
|
||
環境切換
|
@Profile
|
通過設定Environment的ActiveProfiles來設定當前context需要使用的配置環境(類或方法上)
|
在不同環境下使用不同的配置文件
|
@Conditional
|
定義條件化的bean(方法上)
|
通過實現Condition接口,並重寫matches方法,從而決定該bean是否被實例化
|
|
多線程
|
@EnableAsync
|
開啟對異步任務的支持(配置類上)
|
|
@Async
|
聲明異步任務(類或方法上)
|
如果注釋在類上,則該類內所有的方法都是異步方法
|
|
計划任務相關
|
@EnableScheduling
|
開啟計划任務的支持(類上)
|
在配置類上使用
|
@Scheduled
|
申明這是一個任務(方法上)
|
需要線開啟計划任務的支持
計划任務包括cron、fixDelay、fixRate等類型
|
|
測試相關
|
@RunWith
|
運行器,Spring中通常用於對JUnit的支持
|
@RunWith(SpringJUnit4ClassRunner.class)
|
@ContextConfiguration
|
加載配置ApplicationContext |
classes屬性用來加載配置類
@ContextConfiguration(classes={AppConfig.class})
|
|
事務
|
@Transactional
|
使用事務
|
屬性 propagation用來指定事務的傳播行為(默認傳播行為Propagation.REQUIRED)
屬性isolation用來指定事務的隔離級別
|
補充
|
@Import
|
導入配置類
|
|
參考資料
- 汪雲飛《JavaEE開發的顛覆者:Spring Boot實戰》