spring之基礎知識總結


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.補充

使用計划任務,可能會出現org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.concurrent.ScheduledExecutorService' available,這是Spring的拋出的DEBUG信息(雖然會拋出堆棧信息,但是信息級別是DEBUG,不是ERROR),不用關心.
 
條件注解@Conditional
根據不同的條件注冊不同的Bean
具體實現:
1.創建Condition,繼承Condition:用來實現判斷邏輯,條件之間必須是互斥的
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實戰》

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM