ssm(2-1)Spring-IOC/DI

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】

相關文章
相關標籤/搜索