<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>複製代碼
由於spring-context依賴於Spring其餘幾個核心模塊的Jar包,因此使用Spring,導入此座標便可java
ClassPathXmlApplicationContext
獲取容器,這個方法須要配置applicationConfig.xml
來配合初始化容器中的Bean
ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml");
context.refresh();複製代碼
<!-- applicationConfig.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">
<!-- 建立項目根目錄下的src/main/resources目錄,這是maven項目約定的資源文件目錄。 -->
<!-- 建立resources目錄後,記得reimport Maven Project,不然idea識別不了。 -->
<!-- 在resources目錄下,使用idea建立spring context的xml配置文件。 -->
<bean id="customerBean" class="cn.edu.dgut.sai.Customer">
<property name="name" value="hello"/>
</bean>
</beans>複製代碼
AnnotationConfigApplicationContext
獲取容器,這個方法須要配置一個 配置類 來配合初始化容器中的Bean
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
context.refresh();複製代碼
/**
* Configuration:此類爲配置類
* ComponentScan:告知容器掃描此類所在包全部的類以及子包下全部的類的註解
*/
@Configuration
@ComponentScan
public class Config {
}複製代碼
使用Component
在類上面註解,容器進行掃描時,容器自動將此類註冊爲Bean
spring
@Component
public class Player {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}複製代碼
此外,還能夠用@Service
、@Controller
等註解配置Bean,區別在於Component
是通用註解,而Service
則是適用與Service業務層,Controller
適用於Web視圖層編程
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
context.registerBean("UserBean",User.class);
context.refresh();複製代碼
使用Junit
進行測試,再也不須要機械重複地建立一個類,而後加入main
方法,而後在main
方法獲取容器實例ApplicationContext
bash
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = Config.class)
public class SpringTest {
@Test
public void testUser() {
}
}複製代碼
classes須要填寫配置類的字節碼文件網絡
當一個類成爲Bean
,繼承InitializingBean
接口而且實現接口的afterPropertiesSet
方法的時候,當該Bean
被容器註冊而且實例化後的時候,afterPropertiesSet
方法就會被調用(回調)。
app
一樣的,當一個類成爲Bean
,繼承了DisposableBean
接口而且實現接口的destroy方法的時候,當該Bean
被銷燬以前,destroy
方法就會自動被調用(回調)dom
public class User implements InitializingBean, DisposableBean {
private String name;
private String sex;
public User() {
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet回調");
}
@Override
public void destroy() throws Exception {
System.out.println("User: destroy");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
複製代碼
這個接口的做用是令Bean可以獲取容器的實例,進而經過編程的方法進行操做,例以下面,User Bean但願獲取其餘Customer Bean,就建立一個成員變量,經過這個接口獲取容器實例,用成員變量保存容器實例,進而獲取Customer Bean。maven
public class User implements InitializingBean, DisposableBean, ApplicationContextAware {
private String name;
private String sex;
private ApplicationContext context;
public User() {
System.out.println("初始化");
}
@Override
public void destroy() throws Exception {
System.out.println("User: destroy");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet回調");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("applicationContext注入");
this.context = applicationContext;
Customer customerBean = (Customer)this.context.getBean("customerBean");
System.out.println(customerBean);
}
}複製代碼
此註解主要做用是懶加載,一個Bean被ApplicationContext註冊的時候,不會當即實例化,須要等到調用的時候,纔會被實例化ide
定義Bean的範圍,通常是選值爲singleton
或prototype
,singleton
表示爲單例,prototype
表示爲多例函數
回調函數,當一個類註冊爲Bean
,而且繼承BeanPostProcessor
接口,實現其接口的postProcessBeforeInitialization
和postProcessAfterInitialization
方法的時候,在這個容器中,只要有Bean
註冊實例化,就會自動調用此接口的兩個方法。有多少個Bean註冊實例化,就調用多少次。postProcessBeforeInitialization
會在Bean
註冊實例化以前自動被調用,postProcessAfterInitialization
會在Bean
註冊實例化被自動調用。能夠從這兩個方法之中的參數,獲取Bean的實例和註冊爲Bean的命名
注意:當使用context.register方法動態註冊Bean的時候,Bean並不會實例化,不會觸發InitializingBean、ApplicationContextAware等回調函數。當使用getBean的方法的時候,即初始化、實例化Bean,就會觸發Spring容器調用該Bean相關接口的調用
相同:@Component
和@Bean
都是註冊Bean
區別:@Component
是被動的方式,等待Spring容器掃描註解,將類註冊爲Bean,而@Bean
則是主動的方式,主動地將類註冊爲Spring容器的Bean。
用法:@Component是通用寫法,而@Bean一般用於引入外部類(從外部導入Jar包),又想將此類註冊爲Bean,可是又沒有辦法修改外部類的源代碼,就能夠利用@Bean將外部類註冊成爲Bean
@Configuration
@ComponentScan
public class Config {
@Bean("customerBean")
public Customer createCustomer() {
Customer customer = new Customer();
return customer;
}
}複製代碼
注意:依賴的注入,須要依賴已經成爲Bean被Spring容器管理
@Ccomponent
public class User{
@Autowired
private Player player;
}複製代碼
@Component
public class User {
private final Player player;
public User (Player player) { System.out.println("Config構造方法:" + player);
this.player = player;
}
}複製代碼
public class SimpleMovieLister {
private MovieFinder movieFinder;
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}複製代碼
public class SimpleMovieLister {
@Autowired
private ApplicationContext context;
private MovieFinder movieFinder;
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
}複製代碼
根據類型自動注入Bean,當有兩個相同類型的候選者,優先注入有@Primary註解的類
@Configuration
public class MovieConfiguration {
@Bean
@Primary
public MovieCatalog firstMovieCatalog() { ... }
@Bean
public MovieCatalog secondMovieCatalog() { ... }
}複製代碼
在一個配置類裏面,引入其餘配置類
@Configuration
@Import({TestConfig.class,DataSourceConfig.class})
public class ImportConfig {
}複製代碼
代表某個Bean須要依賴其餘Bean
@Configuration
public class TestConfig {
@Bean("depend")
public AccountRepository createJdbcAccountRepo() {
return new JdbcAccountRepository();
}
@Bean
@DependsOn("depend")
public TransferService createTransferSvc() {
return new TransferServiceImpl(createJdbcAccountRepo());
}
}複製代碼
經過Environment能夠獲取JVM屬性集
ApplicationContext ctx = new GenericApplicationContext();
Environment env = ctx.getEnvironment();
boolean containsMyProperty = env.containsProperty("my-property");
System.out.println("Does my environment contain the 'my-property' property? " + containsMyProperty);複製代碼
獲取Spring容器的環境對象,判斷JVM是否存在my-property屬性,若是存在則返回true,不然返回flase
System.getProperties()表示JVM系統屬性集,System.getenv()表示系統環境變量集。能夠用此功能來判斷用戶環境變量是否存在某個屬性值,判斷是否存在而後進行相應的操做
可使用System.getProperties().put(key,value)來自動存入自定義JVM屬性集
也可使用@PropertySource,添加Property到Spring的Enviroment
public void testResourceLoader() throws IOException {
// 本地資源可使用類路徑加載
Resource resource = ctx.getResource("https://www.baidu.com/img/bd_logo1.png");
Path path = Paths.get("C:\Users\admin\Desktop\java");
Files.createDirectories(path);
//@formatter:off
Files.copy(
resource.getInputStream(),
path.resolve(UUID.randomUUID().toString() + resource.getFilename()),
StandardCopyOption.REPLACE_EXISTING
);
//@formatter:on
}複製代碼
注意:使用此處的Paths和Resource須要使用JDK11以上
Spring的容器ApplicationContext是經過ApplicationEvent類和ApplicationListener接口處理事件。ApplicationEvent用於定義事件,ApplicationListener用於監聽事件。
建立自定義事件,須要建立一個自定義事件的類,繼承ApplicationEvent類
public class MyEvent extends ApplicationEvent {
private String name;
private String address;
public MyEvent(Object source, String name, String address) {
super(source);
this.name = name;
this.address = address;
}
}複製代碼
發佈一個自定義事件,須要建立一個類,實現ApplicationEventPublisherAware接口並將其註冊爲Spring Bean的類,而後調用ApplicationEventPublisher發佈事件。這裏,我選擇用EventConfig的配置類實現接口,進而將ApplicationEventPublisher注入到Spring Bean,最後會經過測試類來調用該方法發佈事件
@Configuration
public class EventConfig implements ApplicationEventPublisherAware{
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
@EventListener({MyEvent.class})
public void publisCustomEvent(MyEvent event) {
System.out.println("--------開始監聽事件---------");
System.out.println("--獲取自定義事件--"+event);
System.out.println("--------處理事件-----"+event.getSource());
}
}複製代碼
須要監聽自定義事件的運行,則須要建立一個實現ApplicationListener並註冊爲SpringBean的類,在這裏我選擇使用基於註解的事件監聽器類在EventConfig配置類實現該功能
@Configuration
public class EventConfig implements ApplicationEventPublisherAware{
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
@EventListener({MyEvent.class})
public void publisCustomEvent(MyEvent event) {
System.out.println("--------開始監聽事件---------");
System.out.println("--獲取自定義事件--"+event);
System.out.println(event.getSource());
System.out.println(event.getName()+":"+event.getAddress());
System.out.println("--------處理事件-----");
}
}複製代碼
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = {ImportConfig.class})
public class EventTest {
@Autowired
private ApplicationEventPublisher publisher;
@Autowired
private AopAdvice aopAdvice;
@Test
public void testEvent() {
System.out.println("開始發佈事件");
publisher.publishEvent(new MyEvent("這是一個自定義事件噢","Test","測試自定義監聽"));
System.out.println("結束髮布事件");
}
}複製代碼
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>複製代碼
在Spring配置類基於註解@EnableAspectJAutoProxy開啓AOP支持
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}複製代碼
使用@Aspect
代表這個類爲切面類
@Aspect
public class NotVeryUsefulAspect {
}複製代碼
前置通知 @Before
後置通知 @AfterReturing
異常通知 @AfterThrowing
最終通知 @After
環繞通知 @Around