ssm(2-1)Spring-IOC/DI

1.什么是IOC/DI

1.1 什么是IOC

全称为:Inverse of Control,控制反转,将对在自身对象中的一个内置对象的控制反转,反转后不再由自己本身的对象进行控制这个内置对象的创建,而是由第三方系统去控制这个内置对象的创建。

1.2 什么是DI

全称为Dependency Injection,依赖注入,自身对象中的内置对象是通过依赖第三方系统注入的方式进行创建。

1.3 IOC与DI的关系

IOC就是一种软件设计思想,DI是这种软件设计思想的一个实现。Spring中的核心机制就是DI。

2.基于配置

2.1设值注入

<bean id="helloworld" class="spring1.HelloWorld">
       <property name="name" value="Spring"></property>
</bean>

2.2 构造注入

按顺序
<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】

posted @ 2018-09-21 23:36  fatale  阅读(238)  评论(0编辑  收藏  举报