1.什麼是IOC/DIjava
1.1 什麼是IOCmysql
全稱爲:Inverse of Control,控制反轉,將對在自身對象中的一個內置對象的控制反轉,反轉後再也不由本身自己的對象進行控制這個內置對象的建立,而是由第三方系統去控制這個內置對象的建立。web
1.2 什麼是DIspring
全稱爲Dependency Injection,依賴注入,自身對象中的內置對象是經過依賴第三方系統注入的方式進行建立。sql
1.3 IOC與DI的關係express
IOC就是一種軟件設計思想,DI是這種軟件設計思想的一個實現。Spring中的核心機制就是DI。bash
2.基於配置session
2.1設值注入框架
<bean id="helloworld" class="spring1.HelloWorld"> <property name="name" value="Spring"></property> </bean>
2.2 構造注入dom
按順序 <bean id="car" class="spring1.Car"> <constructor-arg value="audi"></constructor-arg> <constructor-arg value="shanghai"></constructor-arg> <constructor-arg value="3000"></constructor-arg> </bean> 按類型 <bean id="car2" class="spring1.Car"> <constructor-arg value="audi" type="java.lang.String"></constructor-arg> <constructor-arg value="shanghai" type="java.lang.String"></constructor-arg> <constructor-arg value="3000" type="int"></constructor-arg> </bean> 混合使用 <bean id="car3" class="spring1.Car"> <constructor-arg value="audi" type="java.lang.String"></constructor-arg> <constructor-arg value="shanghai" index="1"></constructor-arg> <constructor-arg value="3000" type="int"></constructor-arg> </bean>
2.3 bean之間的相互引用
<!— ref=「id」 --> <bean id="person" class="spring1.Person"> <property name="name" value="tom"></property> <property name="age" value="28"></property> <property name="car" ref="car3"></property> </property>
2.4 內部bean
<bean id="person" class="spring1.Person"> <property name="name" value="tom"></property> <property name="age" value="28"></property> <property name="car"> <bean class="spring1.Car"> <constructor-arg value="audi" type="java.lang.String"></constructor-arg> <constructor-arg value="shanghai" index="1"></constructor-arg> <constructor-arg value="3000" type="int"></constructor-arg> </bean> </property> </bean>
2.5 級聯
<!-- 級聯屬性 可是在 以前必須進行相應的初始化 -->
<property name="car.maxspeed" value="3000"></property>
2.6 集合屬性的構建
List <list> <ref bean="car1"/> <ref bean="car2"/> <ref bean="car3"/> <!-- 內部bean的方式書寫 --> <bean class="spring1.Car"> <constructor-arg value="audi" type="java.lang.String"></constructor-arg> <constructor-arg value="shanghai" index="1"></constructor-arg> <constructor-arg value="3000" type="int"></constructor-arg> </bean> </list> Map <property name="cars"> <map> <entry key="aa" value-ref="car"> </entry> <entry key="bb" value-ref="car1"> </entry> <entry key="cc" value-ref="car2"> </entry> </map> </property> Property <property name="properties"> <props> <prop key="user">root</prop> <prop key="password">cgz12345678</prop> <prop key="jdbcurl">jdbc:mysql:///test</prop> <prop key="driverclass">com.mysql.Driver</prop> </props> </property>
備註:在不能識別構造方法時,會執行最後一個知足條件的構造方法
2.7 實例工廠(用的少)
<bean id="factory" class="cn.spring.test.InstanceFactory" ></bean> <bean id="car1" factory-bean="factory" factory-method="getCar"> <constructor-arg value='audi'></constructor-arg> </bean> private Map<String,Car> cars=new HashMap<>(); public InstanceFactory() { cars.put("audi", new Car("audi", 300000)); cars.put("ford", new Car("ford", 400000)); } public Car getCar(String name){ return cars.get(name); }
2.8 靜態工廠方法(用的少)
static{ cars.put("audi", new Car("audi", 300000)); cars.put("ford", new Car("ford", 400000)); } public static Car getCar(String name){ Car car = cars.get(name); return car; } <bean id="car" class="cn.spring.test.StatiCarFactory" factory-method="getCar"> <constructor-arg value="audi"></constructor-arg> </bean>
2.9 抽像bean
<!--不須要class,abstract=「true」--> <bean id="address2" p:city="shanghai" p:street="dongfang" abstract="true"></bean> <!--parent="address2"--> <bean id="address1" class="spring3.Address"parent="address2" p:street="haoxida"></bean> <!-- depends-on="car" 初始化前須要有一個id爲car的bean--> <bean id="person" class="spring3.Person"p:name="tom" p:address-ref="address1" depends-on="car"></bean>
備註:di依賴注入,一個類依賴另一個類,ioc控制反轉,手動實例化bean變成自動實例化bean
2.10util命名空間
單獨bean
<!-- 配置獨立的集合bean 須要導入util命名空間--> <util:list id="list"> <ref bean="car1"/> <ref bean="car2"/> <ref bean="car3"/> </util:list> <!-- 加載資源文件 --> <util:properties id="resource" location="path"></util:properties> <!-- 暴露靜態field --> <util:constant id="age" static-field="Tese.age"/> <!-- 暴露屬性 --> <util:property-path id="age" path="Test.age"/>
2.11 p命名空間(利用set方法)與c命名空間(利用構造方法)
<!-- p命名空間爲bean的屬性賦值 須要導入p命名空間 --> <bean id="person" class="spring3.Person" p:name="tom" p:address-ref="address" p:car-ref="car" ></bean>
<bean id="person" class="spring3.Person" c:name="tom" c:address-ref="address" c:car-ref="car" ></bean>
2.12 自動裝配
// autowire="byName" 默認值no表示不進行自動裝配,byname與bytype只能選一個 這個方法是存在弊端的 並且弊大於利,byname 根據bean的名字和當前的bean的setter風格的屬性進行裝配,當存在是就裝配,不存在時就不裝配,bytype 根據bean的類型和當前bean的屬性的類型進行自動裝配 若ioc存在一個以上,會拋出異常,通常不多用自動配置,在整合第三方框架的時候會使用
<bean id="person" class="spring3.Person" p:name="tom" autowire="byName"></bean>
2.13 做用域scope
singleton 默認值,表示單例模式,在這個週期類值建立一個bean只初始化一次,在建立容器的時候就已經建立好了
Prototype原型模式,在getbean的時候建立相應的bean,在容器建立的時候不會建立bean ,而是在每次getbean的時候都會建立新的bean
<bean id="car" class="spring3.Car" scope="prototype">
session對應於域對象的session,每次http session時建立一個bean對象,在web中使用時纔有效
request對應於域對象的request,每次http request時建立一個bean對象,在web中使用時纔有效
singleton依賴Prototype的解決方法
<bean id="student" class="cn.test.domain.Student" scope="prototype"/> <bean id="penson" class="cn.test.domain.Person" > <!--name方法名,bean指向id,lookup-method表示會重寫getStudent方法,而後根據bean指向id 獲取並返回,因此在getStudent方法中必須有返回值 --> <lookup-method name="getStudent" bean="student"></lookup-method> </bean>
@Component public class Person { @Lookup public Student getStudent(){ return null; } }
2.14 Spring IOC 容器對 Bean 的生命週期進行管理的過程:
經過構造器或工廠方法建立 Bean 實例,爲 Bean 的屬性設置值和對其餘 Bean 的引用,而後將 Bean 實例傳遞給 Bean 後置處理器的 postProcessBeforeInitialization 方法,調用 Bean 的初始化方法init,將 Bean 實例傳遞給 Bean 後置處理器的 postProcessAfterInitialization方法,Bean 可使用了,當容器關閉時, 調用 Bean 的銷燬方法destroy
備註:
a)init方法和destroy方法的指定(bean無需實現任何接口和繼承,單實例init在建立好實例賦值完成以後執行,多實例在每次調用時執行,單實例destroy在容器銷燬時執行,多實例容器不對其進行管理)
<bean id="car" class="spring5.Car" init-method="init" destroy-method="destroy">
b)bean的後處理器
後處理須要實現 BeanPostProcessor接口,在配置文件中添加初始化 如<bean class="spring5.Mybeanpostprocesse"></bean>;
BeanPostProcessor接口其中的兩個方法
postProcessBeforeInitialization 方法 Bean 的初始化賦值以後@PostConstruct以前調用,
postProcessAfterInitialization方法 Bean 初始化賦值完成以後init以後調用
備註:BeanPostProcessor這個接口比較特殊,在單例模式下,只會在第一次建立容器的時候纔會執行,非單例模式下每次都會執行,BeanPostProcessor的實現類是不會對自身執行BeanPostProcessor接口的兩個方法,而是對其餘的進行管理
類1
public class Person { @Value("張三") String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Person() { System.out.println("------construct------"); } @Lookup public Student getStudent(){ return null; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } @PostConstruct public void postConstruct(){ System.out.println("---PostConstruct---"); } public void init(){ System.out.println("----init----"); } }
類2
@Configuration @ComponentScan("cn.test.life") public class MainConfigOfLifeCycle { @Bean(value = "person",initMethod = "init") public Person getPerson(){ return new Person(); } }
類3
@Component public class MyBeanPostProcessor implements BeanPostProcessor { public MyBeanPostProcessor() { System.out.println("-----------"); } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if(bean instanceof Person){ ((Person) bean).setName("李四"); } System.out.println("postProcessBeforeInitialization"+bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization"+bean); return bean; } }
test
public class Test7 { public static void main(String[] args) { AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); Person person = acac.getBean("person", Person.class); System.out.println(person); } }
輸出結果:
----------- postProcessBeforeInitializationcn.test.config.MainConfigOfLifeCycle$$EnhancerBySpringCGLIB$$c0014f55@799d4f69 postProcessAfterInitializationcn.test.config.MainConfigOfLifeCycle$$EnhancerBySpringCGLIB$$c0014f55@799d4f69 ------construct------ postProcessBeforeInitializationPerson{name='李四'} ---PostConstruct--- ----init---- postProcessAfterInitializationPerson{name='李四'} Person{name='李四'}
備註:執行順序Constructor >postProcessBeforeInitialization> @PostConstruct > InitializingBean > init-method>postProcessAfterInitialization
2.15 引入資源
<context:property-placeholder location="classpath:student.properties" file-encoding="gbk"></context:property-placeholder>//file-encoding編碼集 <bean id="student" class="cn.test.domain.Student" p:name="${person.name}"/>
3.半配置半註解
3.1 組件
@Component: 基本註解, 標識了一個受 Spring 管理的組件
@Respository: 標識持久層組件
@Service: 標識服務層(業務層)組件
@Controller: 標識表現層組件
3.2掃描組件
<context:component-scan base-package="spring7" resource-pattern="*.class"> <!-- contextexclude-filter 排除的類 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/> <!--annotation:根據註解指定expression ,須要提早設置 use-default-filters="false",而後不會在默認添加filter ,這樣context:include-filter纔有做用,不然會默認的添加全部匹配的值--> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/> <!-- assignable根據包名點類名指定expression --> <context:include-filter type="assignable" expression="spring7.UserRepositoryimp"/> </context:component-scan> <context:include-filter> 和 <context:exclude-filter> 子節點支持多種類型的過濾表達式
備註:默認的命名策略: 使用非限定類名, 第一個字母小寫,base-package 屬性指定一個須要掃描的基類包,Spring 容器將會掃描這個基類包裏及其子包中的全部類 ,當須要掃描多個包時, 可使用逗號分隔, 若是僅但願掃描特定的類而非基包下的全部類,可以使用 resource-pattern 屬性過濾特定的類,當 id重複是能夠指定id。
3.3指定id避免id重複
@Component(「id」)等方式指定
@Primary//默認是自動動裝配的首選bean,與@Autowired配合使用
@bean(value=「」)指定
@Qualifier(value)指定,可使用在類,屬性,方法,參數上等,具體見@taget
3.4自動裝配
@Autowired:自動注入,具備參數require(false:表示即便沒有這個屬性相匹配的類也不會報錯),能夠放在參數,方法,屬性,構造器上(具體看@target)
@Resource與@Autowired用法相似,不支持@Primary的功能
@injection與@Autowired同樣,可是少了require屬性,須要導入jar
3.5做用域@scope
@scope(「prototype」) singleton爲默認值,表示單實例,還有request,session,prototype
Prototype原型模式,在getbean的時候建立相應的bean,在容器建立的時候不會建立bean ,而是在每次getbean的時候都會建立新的bean
session對應於域對象的session,每次http session時建立一個bean對象,在web中使用時纔有效
request對應於域對象的request,每次http request時建立一個bean對象,在web中使用時纔有效
4.徹底基於註解(上述提到的註解再也不重複)
4.1基礎註解
@Configuration://配置,可使用AnnotationConfigApplicationContext加載
@Required://例如註解在set方法上,表示必須使用set方法
@Value("李四") //指定值,能夠用在set方法,參數,屬性上,支持spel表達式
@PostConstruct//bean初始化賦值完成以後執行,相似init方法,還有InitializingBean接口的afterPropertiesSet()
方法也相似,只是不一樣的規範
@PreDestroy//容器銷燬bean以前(單實例),對於多實例並不監控銷燬,相似destroy方法,還有DisposableBean接口的destroy()方法
也相似,只是不一樣的規範
@Lazy //延遲加載,第一次調用時加載
@Bean(value="p1",destroyMethod = "destroy",initMethod = "init")/*註解具備返回值的方法,注入bean容器,destroy在銷燬bean以前,init在初始化以後賦值以前,多實例不會加入bean容器管理,因此不會調用detroy方法*/
4.2@ComponentScan
@ComponentScans(): ComponentScan[] value();
@ComponentScan(value = "cn.springannocation.bean",includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Component.class})}, useDefaultFilters = false)
useDefaultFilters:在includeFilters是須要使用,由於是默認加載 ;
FilterType的枚舉值有:ANNOTATION:註解;ASSIGNABLE_TYPE:類型;ASPECTJ:切面表達式(不多用);REGEX:正則;CUSTOM:自定義(須要實現TypeFilter接口)
/*自定義類型過濾器*/ public class MyTypeFilter implements TypeFilter { /*是一個一個來掃描添加的 * 返回值爲true,那麼就會添加到AnnotationConfigApplicationContext容器類 *metadataReader :當前正在掃描的類的信息,包含註解信息,類信息,資源信息等 *MetadataReaderFactory:能夠獲取其餘任何類的信息 * */ @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { System.out.println(metadataReader.getAnnotationMetadata());//註解信息 System.out.println(metadataReader.getClassMetadata());//類信息,例如類名含有xxx的加入容器等 System.out.println(metadataReader.getResource());//路徑等信息 return false; } }
@Configuration @ComponentScan(value = {"cn.test.domain"},includeFilters = @ComponentScan.Filter(type = FilterType.CUSTOM,value = {ScanCustom.class}),useDefaultFilters = false) public class MainConfig1 { }
4.3 @Lookup://在單實例bean依賴多實例bean時使用,通常與@Scope配合使用,單例依賴非單例
@Component public class Person { @LookupStudent public Student getStudent(){//@Lookup以後會重寫該方法,每次getStudent以後具備一個新的Student(Student添加的是@scope(prototype)),該方法須要返回值 return null; } }
4.4 @PropertySource({"classpath:"})//導入多個資源文件,保存在環境變量中
@PropertySource(value = "classpath:student.properties",encoding = "gbk")//encoding編碼集,引入支援
4.5 @Conditional(WindowCondition.class)/*須要實現Condition接口,知足條件的才註冊bean,spring底層大量使用該註解,使用在方法上,表示當前方法須要知足條件,註解在類上,表示全部的都須要知足該條件*/
public class WindowCondition implements Condition { /** * ConditionContext: 上下文信息 * AnnotatedTypeMetadata:註釋信息 */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();//獲取bean工廠 ClassLoader classLoader = context.getClassLoader();//獲取類加載器 Environment environment = context.getEnvironment();//獲取上下文環境 BeanDefinitionRegistry registry = context.getRegistry();//獲取bean的註冊信息 registry.containsBeanDefinition("p");//容器中是否含有p if(environment.getProperty("os.name").contains("Windows")){ System.out.println(environment.getProperty("os.name")); return true; } return false; } }
4.6 @Profile("test")/*默認值defalut,表示被ioc注入,其餘值在沒有被激活的狀況下,不能注入bean,用於數據源的切換等
注入方式:添加運行參數Dspring.profiles.active=test,或者按以下方式激活(按test方式激活)*/
@org.junit.Test public void testProfile(){ acac = new AnnotationConfigApplicationContext(); acac.getEnvironment().setActiveProfiles("test"); acac.register(MainConfig.class); acac.refresh(); String[] names = acac.getBeanDefinitionNames(); for (int i = 0; i < names.length; i++) { System.out.println(names[i]); } }
4.7@Import({Student.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})/*全類名,MyImportSelector須要實現ImportSelector接口,MyImportBeanDefinitionRegistrar須要實現ImportBeanDefinitionRegistrar接口*/
a)MyImportSelector實現ImportSelector接口,使用@Import({MyImportSelector.class})
public class MyImportSelector implements ImportSelector { //AnnotationMetadata:當前標註@Import的全部註解信息 @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { String [] strs={"cn.springannocation.bean.Cat"};//全類名的方式 return strs;//不能返回null,不然會出異常,將strs中的內容注入到bean容器 } }
b)MyImportBeanDefinitionRegistrar實現ImportBeanDefinitionRegistrar接口,使用@Import({MyImportBeanDefinitionRegistrar.class})
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /*importingClassMetadata:當前標註@Import的全部註解信息 BeanDefinitionRegistry:使用registerBeanDefinition方法手動加載*/ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //RootBeanDefinition是BeanDefinition子類 RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Person.class); //Person註冊到BeanDefinitionRegistry中,手動註冊bean registry.registerBeanDefinition("name", rootBeanDefinition);//id名爲name } }
5.其餘
5.1 bean工廠
public class MyFactoryBean implements FactoryBean<Cat> { @Override//獲取bean public Cat getObject() throws Exception { return new Cat(); } @Override//獲取bean的類型 public Class<?> getObjectType() { return Cat.class; } @Override//是不是單例 public boolean isSingleton() { return true; } }
test
@Bean("myFactoryBean") public MyFactoryBean getMyFactoryBean() { return new MyFactoryBean();//默認返回使用的是getObject方法返回的值,假如須要返回MyFactoryBean實例須要添加前綴& }
6.web加載spring
與AOP的相同
7.spel // #{}
7.1字面量
字符串 日期 數值 Boolean和null
7.2建立list集合{a,b,c}及訪問
#{{a,b,c}}
集合的訪問 list[index] map[key]
7.3算術
+, -, *, /, %, ^
利用+號進行字符串鏈接
比較 <, >, ==, <=, >=, lt, gt, eq, le, ge
邏輯 : and, or, not, |
三目運算?: (ternary), ?: (Elvis)
7.4支持正則
7.5方法的調用
與java沒有區別和屬性
#{address.getCity}
value="#{address.city}
7.6類型運算T
#{T(java.lang.Math).PI*80}
7.7容許使用new字段
7.8 容許使用#this 表示spel正在計算的對象
7.9 #root 引用spel的evaluationcontext的root對象
7.10 value="#{'shenz'}" 在沒有找到相應的值至關於value=「shenz」
7.11 id爲car的bean value="#{car}" 至關於ref="car"
7.12 集合的投影
語法 collection.【condition_expr1】
//獲得的新集合時原集合的每一個元素name的屬性值
List.add(new person(name))
#list.!【name】