zoukankan      html  css  js  c++  java
  • Spring(4)

    Spring的Bean的配置形式

    1.基于XML的形式(无需讲解)

    2.基于注解的形式(需要引入AOP的jar包,此jar包实现了AOP的注解)

    当在Spring配置文件中引入类扫描注解命名空间并且指定被扫描的包,Spring就能够从classpath下自动扫描此包以及子包,侦测和实例化具有特定注解的组件

    特定的组件包括:

    --Component:基本注解,标识了一个受Spring管理的组件

    --Respository:标识持久层组件

    --Service:标识服务层(业务层)组件

    --Controller:标识表现层组件

    对于扫描到的组件,Spring有默认的命名策略

    --如果未通过value属性标识组件的名称,那么会使用非限定类名,即取类名的首字母小写

    --通过value属性标识组件名称

    类扫描注解命名空间(Context命名空间):

    xmlns:context="http://www.springframework.org/schema/context"

    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    类扫描注解解析器:

    <context:component-scan base-package=""></context:component-scan>

    如果希望扫描到指定包下的类而非基包下的所有的类,可以使用resource-pattern属性过滤掉特定的类

    <context:component-scan base-package="cn.jc.spring.annotation" resource-pattern="xxx包名/*.class"></context:component-scan>

    context注解解析器的子节点

    --context:include-filter  表示要包含的目标类

    --context:exclude-filter 表示要排除在外的目标类

    该注解解析器下可以拥有若干个子节点,子节点支持多种类型的过滤表达式,常用的类别:annotation,assinable

    <!-- 通过所有标注了XxxAnnotation注解方式的类来过滤 -->

    <!-- 子节点context:exclude-filter 表示指定不包含通过注解方式被SpringIOC容器所管理的那个Bean-->
    <!-- <context:component-scan base-package="cn.jc.spring.annotation">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
      </context:component-scan>

    -->


    <!-- 子节点 context:include-filter 表示指定包含通过注解方法被SpringIOC容器所管理的那个Bean,
    但是use-default-filters属性默认值是true,表示使用默认的注解解析器如Component,Respository,Service,Controller
    如果改成false,表示使用的是 include-filter指定的那个表达式组件,否则将无法过滤
    -->
    <!-- <context:component-scan base-package="cn.jc.spring.annotation" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan> -->

    <!-- 通过所有继承或者扩展XxxService的类 -->

    <!-- 不包含目标类 继承或者扩展那个特定的类-->
    <!-- <context:component-scan base-package="cn.jc.spring.annotation">
        <context:exclude-filter type="assignable" expression="cn.jc.spring.annotation.repository.UserRepository"/>
       </context:component-scan>

    -->
    <!-- 包含目标类继承或者扩展那个特定的类,但是需要使用 use-default-filters设置为false-->
    <context:component-scan base-package="cn.jc.spring.annotation" use-default-filters="false">
      <context:include-filter type="assignable" expression="cn.jc.spring.annotation.repository.UserRepository"/>
    </context:component-scan>

    属性注解

    <context:component-scan> 元素除了扫描包及其子包下的类并且将Bean交给Spring容器装配之外,还可以自动注册AutowiredAnnotationBeanPostProcessor实例的后置处理器,该实例可以自动装配

    具有@Autowired和@Resource以及@Inject注解的属性

    @Autowired注解属性可以放在任意的三个位置

    首先会自动装配具有兼容类型的单个bean属性,也就是会根据类型去匹配IOC容器中被装配的Bean

    其次如果是找不到,就会根据属性名称和IOC容器中被装配的bean的id的名称相匹配,如果相同则匹配成功

    也可以使用注解@Qualifier("")指定属性的名称与所需的被装配的bean的id名称相同(这种情况下通常是在一个借口多个实现类的情况下,为了指明需要使用哪个实现类,可以使用注解@Qualifier("")属性指定使用哪个bean的id),使用这个@Qualifier("")需要使用@Autowired,两个都需要的

    --构造器

    --普通字段(即使是非public)

    直接在字段上加@Autowired,IOC容器会检查这个属性有没有被装配,如果被装配,则自动会给属性赋值

    如果发现这个属性没有被IOC所装配,此时加了注解@Autowired会报错的,如果不想被报错,可以加上属性@Autowired(required=true),输出的结果会是null

    --带参数的方法(setter方法)

    在setter方法上加@Autowired注解,IOC容器中如果属性被装配,那么就可以为属性赋值

    如果是需要指定使用哪个bean对象,可以使用@Qualifier("")和@Autowired,放在setter方法上的

    也可以把@Qualifier("")放在setter方法的带参数的旁边,这样也是可以的

    举个例子:

    @Autowired
    public void setUserJdbcRepositoryImpl1(@Qualifier("userJdbcRepositoryImpl")UserRepository userJdbcRepositoryImpl1) {
    this.userJdbcRepositoryImpl1 = userJdbcRepositoryImpl1;
    }

     除了@Autowired和@Qualifier("")可以为属性赋值之外,还可以使用@Resource(name=""),此属性名称要和IOC容器中被管理的bean的id的名字要相同,如果不指明name属性,就会根据类型相匹配

    @Inject 也是根据类型匹配为属性赋值,但是没有required属性

    Spring的Bean的配置方式

    1.通过全类名的形式(反射机制)

    id在IOC容器中必须是唯一的

    如果id没有指定,Spring自动将权限定性类名作为Bean的名字

    id可以指定多个名字,名字之间可以用逗号、分号或者空格隔开

    2.通过工厂方法(静态工厂方法和实例工厂方法)

    静态工厂方法:简单的说就是通过调用某个类的的静态的方法就可以返回Bean实例,在Spring的配置文件中需要配置静态工厂方法的全类名,指明静态方法,使用constructor-arg来配置静态方法传入的参数

    例子:

    Bean实例:

    public class Car {

        private String broad;

        private double speed;

        public Car(String broad, double speed) {

           this.broad = broad;

           this.speed = speed;

        }

        public Car() {

        }

        @Override

        public String toString() {

           return "Car [broad=" + broad + ", speed=" + speed + "]";

        }

        public void setBroad(String broad) {

           this.broad = broad;

        }

        public void setSpeed(double speed) {

           this.speed = speed;

        }

    }

    静态工厂类:

    /**

     * 静态工厂方法:通过调用某个类的静态方法就可以返回Bean的实例

     * */

    public class StaticCarFactory {

        private static Map<String, Car> cars = new HashMap<String, Car>();

        static{

           cars.put("audio", new Car("audio", 100));

           cars.put("ford", new Car("ford", 200));

        }

        //静态方法

        public static Car getCar(String name){

           return cars.get(name);

        }

    }

    Spring配置文件:

      <!-- 通过静态工厂方法来获取bean实例,注意:不是配置静态工厂方法实例,而是配置bean实例 -->

        <!--

           class属性:指向静态工厂方法的全类名

           factory-method:指向静态工厂方法的名字

           constructor-arg:如果工厂方法需要传入参数,则使用constructor-arg来配置参数

         -->

         <!-- 实际上是通过静态工厂方法的全类名调用静态方法获取的bean -->

        <bean id="car1" class="cn.jc.spring.factory.StaticCarFactory" factory-method="getCar">

           <constructor-arg value="audio"></constructor-arg>

    </bean>

    测试类

    ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-factory.xml");

           Car car = (Car)ctx.getBean("car1");

           System.out.println(car);

    实例工厂方法先创建工厂对象本身,再调用工厂的实例方法来返回Bean实例

    例子

    实例工厂类:

    /**

     * 通过调用实例工厂的方法 即先需要创建工厂对象本身,再调用工厂的实例方法来返回bean的实例

     * */

    public class InstanceCarFactory {

        private Map<String, Car> cars = null;

        public InstanceCarFactory(){

           cars = new HashMap<String, Car>();

           cars.put("audio", new Car("audio", 1000));

           cars.put("fode", new Car("fode", 2000));

        }

        public Car getCar(String name){

           return cars.get(name);

        }

    }

    Spring配置文件:

    <!-- 配置工厂实例 -->

        <bean id="carFactory" class="cn.jc.spring.factory.InstanceCarFactory"></bean>

        <!--通过工厂实例配置工厂方法从而获取bean-->

        <bean id="car2" factory-bean="carFactory" factory-method="getCar">

           <constructor-arg value="fode"></constructor-arg>

    </bean>

    测试类

    Car car2 = (Car)ctx.getBean("car2");

    System.out.println(car2);

    3.通过FactoryBean的方式

    通过实现FactoryBean的接口来调用getObject的方法,从而获取Bean实例

    例子

    实现FactoryBean接口的实现类

    package cn.jc.spring.factorybean;

    import org.springframework.beans.factory.FactoryBean;

    /**

     * 使用FactoryBean的方式来配置Bean

     * 自定义的FactoryBean需要实现spring提供的FactoryBean接口

     * */

    public class CarFactoryBean implements FactoryBean<Car> {

        private String brand;

        public void setBrand(String brand){

           this.brand = brand;

        }

        /**

         * 返回bean的对象

         */

        public Car getObject() throws Exception {

           return new Car(brand, 20000);

        }

        /**

         * 返回bean的类型

         */

        public Class<?> getObjectType() {

           return Car.class;

        }

        /**

         * 是否是单实例的

         */

        public boolean isSingleton() {

           return true;

        }

    }

    Bean类: 

    package cn.jc.spring.factorybean;

    public class Car {

        private String broad;

        private double speed;

        public Car(String broad, double speed) {

           this.broad = broad;

           this.speed = speed;

        }

        public Car() {

        }

        @Override

        public String toString() {

           return "Car [broad=" + broad + ", speed=" + speed + "]";

        }

        public void setBroad(String broad) {

           this.broad = broad;

        }

        public void setSpeed(double speed) {

           this.speed = speed;

        }

    }

    Spring配置文件:

    <?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">

        <!-- 通过FactoryBean来配置bean的实例

           class:指向FactoryBean的全类名

           property:配置FactoryBean的属性    

           返回的实例是FactoryBean的getObject()方法返回的实例

            -->

        <bean id="car" class="cn.jc.spring.factorybean.CarFactoryBean">

           <property name="brand" value="BMW"></property>

        </bean>

    </beans>

    测试main:

    package cn.jc.spring.factorybean;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class Main {

        public static void main(String[] args) {

           ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-factorybean.xml");

           Car car = (Car)ctx.getBean("car");

           System.out.println(car.toString());

        }

    }

    依赖注入的方式

    1.属性注入

    2.构造器注入

      。可以使用index和type来区分重载的构造器,注意构造器必须要有空的构造方法,因为IOC容器要调动空的构造方法创建对象

    属性注入的细节

      。不管是字面值还是引用,赋值都可以使用元素<value/>或者<ref/>元素标签

       。如果字面值中包含特殊字符,可以使用<![CDATA[值]]>

       。可以使用专用的<null/>元素标签作为字符串或者对象的空值

      <property name="name"><null/></property>

      <constructor-arg index="0" type="java.lang.String"><null/></constructor-arg>

      。支持级联属性赋值

    <bean id="helloWorld" class="cn.jc.spring.beans.HelloWorld">

                     <property name="name"><value>xtt</value></property>

                     <property name="car">

                           <!-- 内部Bean -->

                          <bean class="cn.jc.spring.beans.Car">

                          <property name="broad" value="laosi"></property>

                          <property name="speed" value="100"></property>

                          </bean>

                     </property>

                          <!-- 级联属性配置 ,前提是先为car属性赋值,否则会报null-->

                     <property name="car.speed" value="200"></property>

    </bean> 

      。集合属性的赋值

    <bean id="p" class="cn.jc.spring.collections.Person">

        <property name="age" value="10"></property>

        <property name="name" value="cy"></property>

        <!-- 给list集合属性赋值 -->

        <property name="carLists">

             <list>

              <ref bean="car1"/>

              <ref bean="car2"/>

              <!-- 使用内部bean给属性赋值 -->

              <bean class="cn.jc.spring.collections.Car">

                <constructor-arg value="aodi"></constructor-arg>

                <constructor-arg value="0.9"></constructor-arg>

              </bean>

             </list>

        </property>

        <!-- 给数组属性赋值 -->

        <property name="thinks">

          <list>

            <value>t1</value>

            <value>t2</value>

            <value>t3</value>

          </list>

        </property>

        <!-- 给set集合赋值 -->

        <property name="houseLists">

         <set>

           <ref bean="house1"/>

           <ref bean="house2"/>

         </set>

        </property>

      <!--给map集合属性赋值-->

        <property name="moMaps">

          <map>

            <entry key="第一部手机" value-ref="m1"></entry>

            <entry key="第二部手机" value-ref="m2"></entry>

           </map>

         </property>

    </bean>

    <!-- 配置Properties属性值 -->

    <bean id="ds" class="cn.jc.spring.collections.DataSource">

        <property name="properties">

            <props>

             <prop key="user">root</prop>

             <prop key="password">root</prop>

             <prop key="jdbcUrl">jdbc:mysql:///test</prop>

             <prop key="driverClass">com.mysql.jdbc.Driver</prop>

            </props>

        </property>

    </bean>

      。配置单例的集合bean

    配置单例的集合bean,以供多个bean引用,需要打入util的命名空间

    util的命名空间:

    xmlns:util=“http://www.springframework.org/schema/util

    xsi:schemaLocation=http://www.springframework.org/schema/util

    http://www.springframework.org/schema/util/spring-util-2.5.xsd

    例子:

    <util:list id="cars">

           <ref bean="car1"/>

           <ref bean="car2"/>

      </util:list>

      <bean id="p2" class="cn.jc.spring.collections.Person">

           <property name="age" value="100"></property>

           <property name="name" value="jack"></property>

    <property name="carLists" ref="cars"></property>

    </bean>

       。使用P的命名空间

    使用p的命名空间给属性赋值需要导入p的命名空间   

    xmlns:p="http://www.springframework.org/schema/p"

    例子:

    <bean id="car1" class="cn.jc.spring.collections.Car">

               <property name="broad" value="jeep"></property>

               <property name="speed" value="100"></property>

          </bean>

          <bean id="car2" class="cn.jc.spring.collections.Car">

               <constructor-arg index="0" type="java.lang.String" value="benchi"></constructor-arg>

                  <constructor-arg index="1" type="double" value="250"></constructor-arg>

    </bean>

    <!—单例的集合bean-->

    <util:list id="cars">

    <ref bean="car1"/>

    <ref bean="car2"/>

    </util:list>

    <bean id="p3" class="cn.jc.spring.collections.Person" p:age="666" p:name="kkk" p:carLists-ref="cars"></bean>

    自动装配

    1.类型自动装配

    2.名字自动装配

    例子:

    <bean id="address" class="cn.jc.spring.autowir.Address"
    p:city="BJ" p:street="故宫"></bean>

    <bean id="car" class="cn.jc.spring.autowir.Car"
    p:brand="jackqiongs" p:price="2000"></bean>

    <!-- <bean id="person" class="cn.jc.spring.autowir.Person"
    p:name="cyang" p:address-ref="address" p:car-ref="car"></bean> -->

    <!-- 根据名字自动装配,即该bean下的属性从ioc容器中去找相同的bean的id的名称,如果相同,则装配 -->
    <!-- <bean id="person" class="cn.jc.spring.autowir.Person"
    p:name="cyang" autowire="byName"></bean> -->

    <!-- 根据类型自动装配,即该bean下的属性类型与IOC容器中的bean的class类型如果一致,则装配成功,
    如果IOC容器中有多个一样的类型,则会报错 -->
    <bean id="person" class="cn.jc.spring.autowir.Person"
    p:name="cqian" autowire="byType"></bean>

    自动装配的缺点:

                     1.自动装配将会配置bean的所有的属性

                     2.autowire属性要么根据类型,要么根据名称,不可以两者兼而有之

    Bean之间的关系

    1.继承

    继承bean,利用属性parent继承父bean的id值,可以拥有父bean的属性和属性值

    <!-- 抽象bean不能被实例化,只能用来被继承 -->

    <bean id="address" class="cn.jc.spring.relations.Address" p:street="泓阳广场" p:city="NJ" abstract=true></bean>

    <!-- 继承bean的配置 -->

    <bean id="address2" parent="address" p:street="百脑汇"></bean>

    <!-- 抽象bean不能被实例化,只能用来被继承,如果某一个bean的class属性没有被指定,则该bean必须是一个抽象bean -->

    <bean id="address" p:street="泓阳广场" p:city="NJ" abstract="true"></bean>     

    <!-- 继承bean的配置 -->

    <bean id="address2" class="cn.jc.spring.relations.Address" parent="address" p:street="百脑汇"></bean>

    并不是 <bean> 元素里的所有属性都会被继承. 比如: autowire, abstract 等.

    2.依赖

    依赖bean的配置(依赖bean会在本bean实例化之前创建好,依赖bean需要先配置好此bean。如果依赖于多个bean那么可以用逗号或者空格分开):

    <bean id="address" p:street="泓阳广场" p:city="NJ" abstract="true"></bean>

    <bean id="address2" class="cn.jc.spring.autowir.Address" parent="address" p:street="百脑汇"></bean>

    <bean id="car" class="cn.jc.spring.autowir.Car" p:brand="benchi" p:price="10"></bean>

    <bean id="car2" class="cn.jc.spring.autowir.Car" p:brand="benchi2" p:price="102"></bean>

    <bean id="person" class="cn.jc.spring.autowir.Person" p:name="张三" p:address-ref="address2" depends-on="car car2"></bean>

    bean的作用域

    1.单例(singleton)

    单例的bean,非延迟加载,当初始化SpringIOC容器的时候就创建了所有的唯一的实例(通过调用默认的构造方法)

    2.多例(prototype)

    多例的bean,延迟加载,当初始化SpringIOC容器之后,调用getBean方法之后,才会创建相应的实例对象(不唯一)

    使用外部属性文件

    spEL

    SpringIOC容器中bean的生命周期

    1.当初始化IOC容器(单例Bean),调用默认的构造函数,容器会创建单例的bean对象,如果scope是多例的,将会延迟加载,在getBean的时候才会创建对象并获取

    2.为bean的属性赋值,通过调用setter方法

    3.调用bean的初始化方法

    4.当关闭spring的IOC容器的时候,调用销毁方法

    Spring bean的后置处理器

    当在Spring配置文件中配置了Spring bean的后置处理器之后,IOC容器对bean的管理周期将会更加的细致化

    bean 的后置处理器允许在调用初始化方法的前后对bean进行额外处理,他是对IOC容器中的所有的bean实例逐一处理,而非处理单一实例,比如检查bean属性的正确性或者是更改bean属性。对bean处理完之后,可以返回最新的bean对象

    具体的后置处理器需要实现BeanPostProcessor接口,并且覆盖两个方法,还需要在Spring的配置文件中配置Spring bean的后置处理器

    public class MyBeanPostProcessor implements BeanPostProcessor {

          @Override

          public Object postProcessAfterInitialization(Object bean, String beanName)

                     throws BeansException {

               Car car = new Car();

               car.setBrand("fote");

               System.out.println("postProcessAfterInitialization"+car+","+beanName);

               return car;

          }

          @Override

          public Object postProcessBeforeInitialization(Object bean, String beanName)

                     throws BeansException {

               System.out.println("postProcessBeforeInitialization"+bean+","+beanName);

               return bean;

          }

    }

    <bean id="carcar" class="cn.jc.spring.cycle.Car" init-method="init2" destroy-method="destory" scope="singleton" lazy-init="default">
      <property name="brand" value="#{'audio'}"></property>
    </bean>
    <bean class="cn.jc.spring.cycle.MyBeanPostProcessor"></bean>

    实体类:

    package cn.jc.spring.cycle;

    public class Car {
    private String brand;

    public Car(){
    System.out.println("cars constructor...");
    }
    public void setBrand(String brand){
    System.out.println("setBrand...");
    this.brand = brand;
    }
    public void init2(){
    System.out.println("init....");
    }
    public void destory(){
    System.out.println("destory...");
    }

    @Override
    public String toString() {
    return "Car [brand=" + brand + "]";
    }
    }

    测试类:

    package cn.jc.spring.cycle;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class Main {
    public static void main(String[] args) {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-cycle.xml");
    Car car = (Car)ctx.getBean("carcar");
    System.out.println(car);
    ConfigurableApplicationContext cac = (ConfigurableApplicationContext)ctx;
    cac.close();
    }
    }

    此时Spring IOC容器对bean的生命周期的管理:

    1. 调用默认的构造函数,创建bean对象(scope单例非延迟),如果scope是多例时,将会延迟加载,在getBean时才会调用默认的构造方法,创建bean对象
    2. 为bean的属性赋值或者是对其他bean的引用
    3. 将 Bean 实例传递给 Bean 后置处理器的postProcessBeforeInitialization 方法
    4. 调用bean的初始化方法
    5. 将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法
    6. 可以使用Bean对象了
    7. 当关闭spring的IOC容器时,调用销毁方法

    Spring4.x的新特性

    泛型依赖注入

     子类继承父类,子类注入,父类获取的是子类的泛型的对象

    举个例子:

    BaseService类:

    package cn.jc.spring.generic.di;

    import org.springframework.beans.factory.annotation.Autowired;

    public class BaseService<T> {
    @Autowired
    protected BaseRepository<T> repository;
        public void add(){
        System.out.println("add ....");
        System.out.println(repository);
      }
    }

    BaseRespository类:

    package cn.jc.spring.generic.di;

      public class BaseRepository<T> {

    }

    UserService类

    package cn.jc.spring.generic.di;

    import org.springframework.stereotype.Service;

    @Service
    public class UserService extends BaseService<User> {

    }

    UserRepository

    package cn.jc.spring.generic.di;

    import org.springframework.stereotype.Repository;

    @Repository
    public class UserRepository extends BaseRepository<User> {

    }

    User类

    package cn.jc.spring.generic.di;

      public class User {

    }

    beans-generic-di.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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <context:component-scan base-package="cn.jc.spring.generic.di"></context:component-scan>

    </beans>

    Main 测试类

    package cn.jc.spring.generic.di;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;

    public class Main {
        public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans-generic-di.xml");
        UserService userService = (UserService)ac.getBean("userService");
        userService.add();
      }
    }

     

    输出的结果:

    add ....
    cn.jc.spring.generic.di.UserRepository@5684ce7a

     

  • 相关阅读:
    重构drf后的环境变量配置
    分离的前后台交互
    虚拟环境的搭建
    Python
    Python
    Python
    Python操作MongoDb数据库
    Python操作SQLite/MySQL/LMDB
    数据库-如何创建SQL Server身份验证用户
    Python
  • 原文地址:https://www.cnblogs.com/caoyang-q/p/5310229.html
Copyright © 2011-2022 走看看