//配置類==配置文件
@Configuration //告訴Spring這是一個配置類
@ComponentScans(
value = {
@ComponentScan(value="com.atguigu",includeFilters = {
/* @Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),*/
@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
},useDefaultFilters = false)
}
)
//@ComponentScan value:指定要掃描的包
//excludeFilters = Filter[] :指定掃描的時候按照什麼規則排除那些組件
//includeFilters = Filter[] :指定掃描的時候只需要包含哪些組件
//FilterType.ANNOTATION:按照註解
//FilterType.ASSIGNABLE_TYPE:按照給定的類型;
//FilterType.ASPECTJ:使用ASPECTJ表達式
//FilterType.REGEX:使用正則指定
//FilterType.CUSTOM:使用自定義規則
public class MainConfig {
//給容器中註冊一個Bean;類型爲返回值的類型,id默認是用方法名作爲id
@Bean("person")
public Person person01(){
return new Person("lisi", 20);
}
}
public class MyTypeFilter implements TypeFilter {
/**
* metadataReader:讀取到的當前正在掃描的類的信息
* metadataReaderFactory:可以獲取到其他任何類信息的
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// TODO Auto-generated method stub
//獲取當前類註解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//獲取當前正在掃描的類的類信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//獲取當前類資源(類的路徑)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("--->"+className);
if(className.contains("er")){
return true;
}
return false;
}
}
//類中組件統一設置。滿足當前條件,這個類中配置的所有bean註冊才能生效;
@Conditional({WindowsCondition.class})
@Configuration
@Import({Color.class,Red.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
//@Import導入組件,id默認是組件的全類名
public class MainConfig2 {
//默認是單實例的
/**
* ConfigurableBeanFactory#SCOPE_PROTOTYPE
* @see ConfigurableBeanFactory#SCOPE_SINGLETON
* @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST request
* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION sesssion
* @return\
* @Scope:調整作用域
* prototype:多實例的:ioc容器啓動並不會去調用方法創建對象放在容器中。
* 每次獲取的時候纔會調用方法創建對象;
* singleton:單實例的(默認值):ioc容器啓動會調用方法創建對象放到ioc容器中。
* 以後每次獲取就是直接從容器(map.get())中拿,
* request:同一次請求創建一個實例
* session:同一個session創建一個實例
*
* 懶加載:
* 單實例bean:默認在容器啓動的時候創建對象;
* 懶加載:容器啓動不創建對象。第一次使用(獲取)Bean創建對象,並初始化;
*
*/
// @Scope("prototype")
@Lazy
@Bean("person")
public Person person(){
System.out.println("給容器中添加Person....");
return new Person("張三", 25);
}
/**
* @Conditional({Condition}) : 按照一定的條件進行判斷,滿足條件給容器中註冊bean
*
* 如果系統是windows,給容器中註冊("bill")
* 如果是linux系統,給容器中註冊("linus")
*/
@Bean("bill")
public Person person01(){
return new Person("Bill Gates",62);
}
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02(){
return new Person("linus", 48);
}
/**
* 給容器中註冊組件;
* 1)、包掃描+組件標註註解(@Controller/@Service/@Repository/@Component)[自己寫的類]
* 2)、@Bean[導入的第三方包裏面的組件]
* 3)、@Import[快速給容器中導入一個組件]
* 1)、@Import(要導入到容器中的組件);容器中就會自動註冊這個組件,id默認是全類名
* 2)、ImportSelector:返回需要導入的組件的全類名數組;
* 3)、ImportBeanDefinitionRegistrar:手動註冊bean到容器中
* 4)、使用Spring提供的 FactoryBean(工廠Bean);
* 1)、默認獲取到的是工廠bean調用getObject創建的對象
* 2)、要獲取工廠Bean本身,我們需要給id前面加一個&
* &colorFactoryBean
*/
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
}
/**
* 自動裝配;
* Spring利用依賴注入(DI),完成對IOC容器中中各個組件的依賴關係賦值;
*
* 1)、@Autowired:自動注入:
* 1)、默認優先按照類型去容器中找對應的組件:applicationContext.getBean(BookDao.class);找到就賦值
* 2)、如果找到多個相同類型的組件,再將屬性的名稱作爲組件的id去容器中查找
* applicationContext.getBean("bookDao")
* 3)、@Qualifier("bookDao"):使用@Qualifier指定需要裝配的組件的id,而不是使用屬性名
* 4)、自動裝配默認一定要將屬性賦值好,沒有就會報錯;
* 可以使用@Autowired(required=false);
* 5)、@Primary:讓Spring進行自動裝配的時候,默認使用首選的bean;
* 也可以繼續使用@Qualifier指定需要裝配的bean的名字
* BookService{
* @Autowired
* BookDao bookDao;
* }
*
* 2)、Spring還支持使用@Resource(JSR250)和@Inject(JSR330)[java規範的註解]
* @Resource:
* 可以和@Autowired一樣實現自動裝配功能;默認是按照組件名稱進行裝配的;
* 沒有能支持@Primary功能沒有支持@Autowired(reqiured=false);
* @Inject:
* 需要導入javax.inject的包,和Autowired的功能一樣。沒有required=false的功能;
* @Autowired:Spring定義的; @Resource、@Inject都是java規範
*
* AutowiredAnnotationBeanPostProcessor:解析完成自動裝配功能;
*
* 3)、 @Autowired:構造器,參數,方法,屬性;都是從容器中獲取參數組件的值
* 1)、[標註在方法位置]:@Bean+方法參數;參數從容器中獲取;默認不寫@Autowired效果是一樣的;都能自動裝配
* 2)、[標在構造器上]:如果組件只有一個有參構造器,這個有參構造器的@Autowired可以省略,參數位置的組件還是可以自動從容器中獲取
* 3)、放在參數位置:
*
* 4)、自定義組件想要使用Spring容器底層的一些組件(ApplicationContext,BeanFactory,xxx);
* 自定義組件實現xxxAware;在創建對象的時候,會調用接口規定的方法注入相關組件;Aware;
* 把Spring底層一些組件注入到自定義的Bean中;
* xxxAware:功能使用xxxProcessor;
* ApplicationContextAware==》ApplicationContextAwareProcessor;
*
*
* @author lfy
*
*/
@Configuration
@ComponentScan({"com.atguigu.service","com.atguigu.dao",
"com.atguigu.controller","com.atguigu.bean"})
public class MainConifgOfAutowired {
@Primary
@Bean("bookDao2")
public BookDao bookDao(){
BookDao bookDao = new BookDao();
bookDao.setLable("2");
return bookDao;
}
/**
* @Bean標註的方法創建對象的時候,方法參數的值從容器中獲取
* @param car
* @return
*/
@Bean
public Color color(Car car){
Color color = new Color();
color.setCar(car);
return color;
}
}
/**
* Profile:
* Spring爲我們提供的可以根據當前環境,動態的激活和切換一系列組件的功能;
*
* 開發環境、測試環境、生產環境;
* 數據源:(/A)(/B)(/C);
*
*
* @Profile:指定組件在哪個環境的情況下才能被註冊到容器中,不指定,任何環境下都能註冊這個組件
*
* 1)、加了環境標識的bean,只有這個環境被激活的時候才能註冊到容器中。默認是default環境
* 2)、寫在配置類上,只有是指定的環境的時候,整個配置類裏面的所有配置才能開始生效
* 3)、沒有標註環境標識的bean在,任何環境下都是加載的;
*/
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
@Value("${db.user}")
private String user;
private StringValueResolver valueResolver;
private String driverClass;
@Bean
public Yellow yellow(){
return new Yellow();
}
@Profile("test")
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("dev")
@Bean("devDataSource")
public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("prod")
@Bean("prodDataSource")
public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
// TODO Auto-generated method stub
this.valueResolver = resolver;
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
}
}
/**
* bean的生命週期:
* bean創建---初始化----銷燬的過程
* 容器管理bean的生命週期;
* 我們可以自定義初始化和銷燬方法;容器在bean進行到當前生命週期的時候來調用我們自定義的初始化和銷燬方法
*
* 構造(對象創建)
* 單實例:在容器啓動的時候創建對象
* 多實例:在每次獲取的時候創建對象\
*
* BeanPostProcessor.postProcessBeforeInitialization
* 初始化:
* 對象創建完成,並賦值好,調用初始化方法。。。
* BeanPostProcessor.postProcessAfterInitialization
* 銷燬:
* 單實例:容器關閉的時候
* 多實例:容器不會管理這個bean;容器不會調用銷燬方法;
*
*
* 遍歷得到容器中所有的BeanPostProcessor;挨個執行beforeInitialization,
* 一但返回null,跳出for循環,不會執行後面的BeanPostProcessor.postProcessorsBeforeInitialization
*
* BeanPostProcessor原理
* populateBean(beanName, mbd, instanceWrapper);給bean進行屬性賦值
* initializeBean
* {
* applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
* invokeInitMethods(beanName, wrappedBean, mbd);執行自定義初始化
* applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
*}
*
*
*
* 1)、指定初始化和銷燬方法;
* 通過@Bean指定init-method和destroy-method;
* 2)、通過讓Bean實現InitializingBean(定義初始化邏輯),
* DisposableBean(定義銷燬邏輯);
* 3)、可以使用JSR250;
* @PostConstruct:在bean創建完成並且屬性賦值完成;來執行初始化方法
* @PreDestroy:在容器銷燬bean之前通知我們進行清理工作
* 4)、BeanPostProcessor【interface】:bean的後置處理器;
* 在bean初始化前後進行一些處理工作;
* postProcessBeforeInitialization:在初始化之前工作
* postProcessAfterInitialization:在初始化之後工作
*
* Spring底層對 BeanPostProcessor 的使用;
* bean賦值,注入其他組件,@Autowired,生命週期註解功能,@Async,xxx BeanPostProcessor;
*
* @author lfy
*
*/
@ComponentScan("com.atguigu.bean")
@Configuration
public class MainConfigOfLifeCycle {
//@Scope("prototype")
@Bean(initMethod="init",destroyMethod="detory")
public Car car(){
return new Car();
}
}
/**
* AOP:【動態代理】
* 指在程序運行期間動態的將某段代碼切入到指定方法指定位置進行運行的編程方式;
*
* 1、導入aop模塊;Spring AOP:(spring-aspects)
* 2、定義一個業務邏輯類(MathCalculator);在業務邏輯運行的時候將日誌進行打印(方法之前、方法運行結束、方法出現異常,xxx)
* 3、定義一個日誌切面類(LogAspects):切面類裏面的方法需要動態感知MathCalculator.div運行到哪裏然後執行;
* 通知方法:
* 前置通知(@Before):logStart:在目標方法(div)運行之前運行
* 後置通知(@After):logEnd:在目標方法(div)運行結束之後運行(無論方法正常結束還是異常結束)
* 返回通知(@AfterReturning):logReturn:在目標方法(div)正常返回之後運行
* 異常通知(@AfterThrowing):logException:在目標方法(div)出現異常以後運行
* 環繞通知(@Around):動態代理,手動推進目標方法運行(joinPoint.procced())
* 4、給切面類的目標方法標註何時何地運行(通知註解);
* 5、將切面類和業務邏輯類(目標方法所在類)都加入到容器中;
* 6、必須告訴Spring哪個類是切面類(給切面類上加一個註解:@Aspect)
* [7]、給配置類中加 @EnableAspectJAutoProxy 【開啓基於註解的aop模式】
* 在Spring中很多的 @EnableXXX;
*
* 三步:
* 1)、將業務邏輯組件和切面類都加入到容器中;告訴Spring哪個是切面類(@Aspect)
* 2)、在切面類上的每一個通知方法上標註通知註解,告訴Spring何時何地運行(切入點表達式)
* 3)、開啓基於註解的aop模式;@EnableAspectJAutoProxy
*
* AOP原理:【看給容器中註冊了什麼組件,這個組件什麼時候工作,這個組件的功能是什麼?】
* @EnableAspectJAutoProxy;
* 1、@EnableAspectJAutoProxy是什麼?
* @Import(AspectJAutoProxyRegistrar.class):給容器中導入AspectJAutoProxyRegistrar
* 利用AspectJAutoProxyRegistrar自定義給容器中註冊bean;BeanDefinetion
* internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
*
* 給容器中註冊一個AnnotationAwareAspectJAutoProxyCreator;
*
* 2、 AnnotationAwareAspectJAutoProxyCreator:
* AnnotationAwareAspectJAutoProxyCreator
* ->AspectJAwareAdvisorAutoProxyCreator
* ->AbstractAdvisorAutoProxyCreator
* ->AbstractAutoProxyCreator
* implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
* 關注後置處理器(在bean初始化完成前後做事情)、自動裝配BeanFactory
*
* AbstractAutoProxyCreator.setBeanFactory()
* AbstractAutoProxyCreator.有後置處理器的邏輯;
*
* AbstractAdvisorAutoProxyCreator.setBeanFactory()-》initBeanFactory()
*
* AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()
*
*
* 流程:
* 1)、傳入配置類,創建ioc容器
* 2)、註冊配置類,調用refresh()刷新容器;
* 3)、registerBeanPostProcessors(beanFactory);註冊bean的後置處理器來方便攔截bean的創建;
* 1)、先獲取ioc容器已經定義了的需要創建對象的所有BeanPostProcessor
* 2)、給容器中加別的BeanPostProcessor
* 3)、優先註冊實現了PriorityOrdered接口的BeanPostProcessor;
* 4)、再給容器中註冊實現了Ordered接口的BeanPostProcessor;
* 5)、註冊沒實現優先級接口的BeanPostProcessor;
* 6)、註冊BeanPostProcessor,實際上就是創建BeanPostProcessor對象,保存在容器中;
* 創建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
* 1)、創建Bean的實例
* 2)、populateBean;給bean的各種屬性賦值
* 3)、initializeBean:初始化bean;
* 1)、invokeAwareMethods():處理Aware接口的方法回調
* 2)、applyBeanPostProcessorsBeforeInitialization():應用後置處理器的postProcessBeforeInitialization()
* 3)、invokeInitMethods();執行自定義的初始化方法
* 4)、applyBeanPostProcessorsAfterInitialization();執行後置處理器的postProcessAfterInitialization();
* 4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)創建成功;--》aspectJAdvisorsBuilder
* 7)、把BeanPostProcessor註冊到BeanFactory中;
* beanFactory.addBeanPostProcessor(postProcessor);
* =======以上是創建和註冊AnnotationAwareAspectJAutoProxyCreator的過程========
*
* AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor
* 4)、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;創建剩下的單實例bean
* 1)、遍歷獲取容器中所有的Bean,依次創建對象getBean(beanName);
* getBean->doGetBean()->getSingleton()->
* 2)、創建bean
* 【AnnotationAwareAspectJAutoProxyCreator在所有bean創建之前會有一個攔截,InstantiationAwareBeanPostProcessor,會調用postProcessBeforeInstantiation()】
* 1)、先從緩存中獲取當前bean,如果能獲取到,說明bean是之前被創建過的,直接使用,否則再創建;
* 只要創建好的Bean都會被緩存起來
* 2)、createBean();創建bean;
* AnnotationAwareAspectJAutoProxyCreator 會在任何bean創建之前先嚐試返回bean的實例
* 【BeanPostProcessor是在Bean對象創建完成初始化前後調用的】
* 【InstantiationAwareBeanPostProcessor是在創建Bean實例之前先嚐試用後置處理器返回對象的】
* 1)、resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation
* 希望後置處理器在此能返回一個代理對象;如果能返回代理對象就使用,如果不能就繼續
* 1)、後置處理器先嚐試返回對象;
* bean = applyBeanPostProcessorsBeforeInstantiation():
* 拿到所有後置處理器,如果是InstantiationAwareBeanPostProcessor;
* 就執行postProcessBeforeInstantiation
* if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
*
* 2)、doCreateBean(beanName, mbdToUse, args);真正的去創建一個bean實例;和3.6流程一樣;
* 3)、
*
*
* AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】 的作用:
* 1)、每一個bean創建之前,調用postProcessBeforeInstantiation();
* 關心MathCalculator和LogAspect的創建
* 1)、判斷當前bean是否在advisedBeans中(保存了所有需要增強bean)
* 2)、判斷當前bean是否是基礎類型的Advice、Pointcut、Advisor、AopInfrastructureBean,
* 或者是否是切面(@Aspect)
* 3)、是否需要跳過
* 1)、獲取候選的增強器(切面裏面的通知方法)【List<Advisor> candidateAdvisors】
* 每一個封裝的通知方法的增強器是 InstantiationModelAwarePointcutAdvisor;
* 判斷每一個增強器是否是 AspectJPointcutAdvisor 類型的;返回true
* 2)、永遠返回false
*
* 2)、創建對象
* postProcessAfterInitialization;
* return wrapIfNecessary(bean, beanName, cacheKey);//包裝如果需要的情況下
* 1)、獲取當前bean的所有增強器(通知方法) Object[] specificInterceptors
* 1、找到候選的所有的增強器(找哪些通知方法是需要切入當前bean方法的)
* 2、獲取到能在bean使用的增強器。
* 3、給增強器排序
* 2)、保存當前bean在advisedBeans中;
* 3)、如果當前bean需要增強,創建當前bean的代理對象;
* 1)、獲取所有增強器(通知方法)
* 2)、保存到proxyFactory
* 3)、創建代理對象:Spring自動決定
* JdkDynamicAopProxy(config);jdk動態代理;
* ObjenesisCglibAopProxy(config);cglib的動態代理;
* 4)、給容器中返回當前組件使用cglib增強了的代理對象;
* 5)、以後容器中獲取到的就是這個組件的代理對象,執行目標方法的時候,代理對象就會執行通知方法的流程;
*
*
* 3)、目標方法執行 ;
* 容器中保存了組件的代理對象(cglib增強後的對象),這個對象裏面保存了詳細信息(比如增強器,目標對象,xxx);
* 1)、CglibAopProxy.intercept();攔截目標方法的執行
* 2)、根據ProxyFactory對象獲取將要執行的目標方法攔截器鏈;
* List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
* 1)、List<Object> interceptorList保存所有攔截器 5
* 一個默認的ExposeInvocationInterceptor 和 4個增強器;
* 2)、遍歷所有的增強器,將其轉爲Interceptor;
* registry.getInterceptors(advisor);
* 3)、將增強器轉爲List<MethodInterceptor>;
* 如果是MethodInterceptor,直接加入到集合中
* 如果不是,使用AdvisorAdapter將增強器轉爲MethodInterceptor;
* 轉換完成返回MethodInterceptor數組;
*
* 3)、如果沒有攔截器鏈,直接執行目標方法;
* 攔截器鏈(每一個通知方法又被包裝爲方法攔截器,利用MethodInterceptor機制)
* 4)、如果有攔截器鏈,把需要執行的目標對象,目標方法,
* 攔截器鏈等信息傳入創建一個 CglibMethodInvocation 對象,
* 並調用 Object retVal = mi.proceed();
* 5)、攔截器鏈的觸發過程;
* 1)、如果沒有攔截器執行執行目標方法,或者攔截器的索引和攔截器數組-1大小一樣(指定到了最後一個攔截器)執行目標方法;
* 2)、鏈式獲取每一個攔截器,攔截器執行invoke方法,每一個攔截器等待下一個攔截器執行完成返回以後再來執行;
* 攔截器鏈的機制,保證通知方法與目標方法的執行順序;
*
* 總結:
* 1)、 @EnableAspectJAutoProxy 開啓AOP功能
* 2)、 @EnableAspectJAutoProxy 會給容器中註冊一個組件 AnnotationAwareAspectJAutoProxyCreator
* 3)、AnnotationAwareAspectJAutoProxyCreator是一個後置處理器;
* 4)、容器的創建流程:
* 1)、registerBeanPostProcessors()註冊後置處理器;創建AnnotationAwareAspectJAutoProxyCreator對象
* 2)、finishBeanFactoryInitialization()初始化剩下的單實例bean
* 1)、創建業務邏輯組件和切面組件
* 2)、AnnotationAwareAspectJAutoProxyCreator攔截組件的創建過程
* 3)、組件創建完之後,判斷組件是否需要增強
* 是:切面的通知方法,包裝成增強器(Advisor);給業務邏輯組件創建一個代理對象(cglib);
* 5)、執行目標方法:
* 1)、代理對象執行目標方法
* 2)、CglibAopProxy.intercept();
* 1)、得到目標方法的攔截器鏈(增強器包裝成攔截器MethodInterceptor)
* 2)、利用攔截器的鏈式機制,依次進入每一個攔截器進行執行;
* 3)、效果:
* 正常執行:前置通知-》目標方法-》後置通知-》返回通知
* 出現異常:前置通知-》目標方法-》後置通知-》異常通知
*
*
*
*/
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
//業務邏輯類加入容器中
@Bean
public MathCalculator calculator(){
return new MathCalculator();
}
//切面類加入到容器中
@Bean
public LogAspects logAspects(){
return new LogAspects();
}
}
//SpringMVC只掃描Controller;子容器
//useDefaultFilters=false 禁用默認的過濾規則;
@ComponentScan(value="com.atguigu",includeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
},useDefaultFilters=false)
@EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
//定製
//視圖解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
// TODO Auto-generated method stub
//默認所有的頁面都從 /WEB-INF/ xxx .jsp
//registry.jsp();
registry.jsp("/WEB-INF/views/", ".jsp");
}
//靜態資源訪問
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
// TODO Auto-generated method stub
configurer.enable();
}
//攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// TODO Auto-generated method stub
//super.addInterceptors(registry);
registry.addInterceptor(new MyFirstInterceptor()).addPathPatterns("/**");
}
}