spring教程

springIOC 
#控制反转
#创建对象和管理对象的关系,降低他们的耦合度
#是其他功能的基础
#spring容器是IOC的核心
springAOP
面向切面编程,可以处理一切对象的共同业务,降低共同业务和对象之间的耦合度
spring MVC
自动实现mvc给代码分层,进一步降低servlet和jsp内部的耦合度
spring整和
 
管理jdbc,提高开发效率,整合mybatis,hibernate,structs2,降低技术中对象的耦合度
 
1.spring容器
1.1 BeanFactory和ApplicationContext是容器的两个接口,后者继承前者,常用后者
ApplicationContext  a=new ClassPathXmlApplicationContext(str)
实例化容器后从ClassPath路径下读取配置文件,bean类交给spring容器创建。
创建是通过反射和代理类调用实现的。
1.2 Spring容器新建Bean对象.
先实例化容器,在配置文件中添加beean标签,bean取名用id或者name。
<bean id="arraylist" class="java.util.ArrayList"></bean>
再从容器中获取指定id的bean List list = (ArrayList)a.getBean(“arraylist”)
或者 List list = a.getBean(“arraylist”,ArrayList.class)
在配置文件中创建Bean标签
##-静态工厂方法实例化(了解)
一些类构造方法是私有的,只能通过类的静态方法创建对象,method是要调用的方法。使用 construtor-arg 元素为工厂方法传递方法参数
<bean id="calendar" class="java.util.Calendar" factory-method="getInstance">
<constrcutor-arg index=0 value="dsfds"></constuctor>
</bean>
##-实例工厂方法实例化(了解),必须引用在容器中声明过的对象。
非静态方法的创建对象
    <bean factory-bean="calendar" factory-method="getTime" id="obj3"></bean>   factory-bean是要调用对象的名称id,
1.3 Bean的作用域:spring默认的singlon只创建一个类的一个实例,可以更改bean的作用域。Bean标签中添加scope=”prototype”,表示一个容器实例化多个实例。request表示对象的声明周期和request相同,session原理相同
1.4 Bean的生命周期
Spring管理bean 的生命周期,让spring自动调用该bean的初始化和销毁方法。在bean的标签中添加<bean id="demo" class="bean.BeanDemo" init-method="init" destroy-method="destroy"></bean>在容器创建之后自动调用init方法,容器关闭时自动调用destroy销毁。
销毁方法只适合单例模式,如果想要关闭容器.
在顶级bean也可以添加default-init-method和destroy方法,(了解)
1.5 bean延迟实例化
如果想bean在获取时初始化,可以在bean标签中添加lazy-init=“true”,只对单例的bean有效。
2 spring IOC 控制反转
2.1 对象的依赖关系由容器处理,容器采用DI方式是实现IOC
 
2.2 DI: 依赖注入,有两种方式setter注入和构造器注入实现。(8大基本数据类型注入和引用类型注入)
##setter注入:  通过bean类(有无参构造器)的set方法注入,在配置文件中的增添property标签
<bean id="" class="">
<property name="" value=""/>
</bean>
 
##注入的是基本数据类型、String、基本封装类型,value里写字符串,spring能自动转型进行参数注入
##bean注入的是另一个bean,把value替换成ref,<property name="computure" ref="computer"/> ref的值是另一个bean的id,或者用ref标签<ref bean=""/>全局查找  <ref local=""/>当前文件查找bean,都是用来引用bean
 
## p命令空间注入  需要引入<xml:p=h"http://www.springframework.org/schema/p">   <bean id="message" class="bean.MessageTest" p:name="zhouyang" //直接值, p:dao-ref="beanId" 表示dao是一个引用对象>    用于set注入
## c命令空间注入   需要引入<xml: c="http://www.springframework.org/schema/c"/>   <bean id="message" class="bean.MessageTest" c:name="zhouyang" c:dao-ref="beanId">   用于构造器注入
 
补充:在xml配置文件中可以读取properties配置文件,
方法一:<util:properties id=”p”location=”classPath:xx.properties”/>,后面使用spring表达式#{}使用
方法二:spring2.0中,声明一个bean,读取properties,在后面使用${key}读取属性值
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classPath:x.properties</value>
</property>
</bean>
方式三:spring2.5中,<context:property-placeholer location="classpath:xx.xml"/>  读取${key}
 
 ##构造器注入  在bean的类中有参数的构造器(bean类可以有无参构造器,写上是个好习惯),bean的参数必须传入,往往是为了强制  注入参数。
 
<bean id="mobile" class="bean.MobileCellphone">
//根据index注入
<constructor-arg index="0" value="ARM"/> //注入基本类型,用value
<constructor-arg index="1" ref="listMessage/>   //注入其他bean
//根据类型注入
<constructor-arg type="java.lang.String" value="zhouyang">
##bean引用补充
补充:对于ref引用的bean,也可以这样声明成内部bean,set注入或者构造器注入都可以
<bean id="CustomerBean" class="com.yiibai.common.Customer">
                <property name="person">
                        <bean class="com.yiibai.common.Person">
                                <property name="name" value="yiibai" />
                                <property name="address" value="address1" />
                                <property name="age" value="28" />
                        </bean>
                </property>
     <constructor-arg>
  <bean class="com.yiibai.common.Person">
                                <property name="name" value="yiibai" />
                                <property name="address" value="address1" />
                                <property name="age" val‘’ue="28" />
                        </bean>
</constructor-arg>
        </bean>
##注入集合:给list(数组) set map properties集合注入参数(简单值或者引用表示集合)
<property name="list">
<list>
<value>北京</value>
<value>上海</value>
<value>天津</value>
<ref bean="address1"/>
</list>
</property>
<property name="set">
<set>
<value></value>
<value>张三</value>
<ref bean="address2"/>
</set>
</property>
<property name="map">
<map>
<entry key="jsd1604" value="80"/>
<entry key="jsd1605" value="90"/>
<entry key ="two" value-ref="address1"/>
</map>
</property>
<property name="properties">
<props>
<prop key="user">openman</prop>
<prop key="pwd">123456</prop>
</props>
</property>
##引用的方式注入集合,先申明一个util标签,在bean中引用它.
<util:list id="listMessage">
    <value>张三</value>
    <value>李四</value>
    </util:list>
    <bean id="message" class="bean.MessageTest">
    <property name="list" ref="listMessage"/>
    </bean>
2.3 xml配置文件可以继承bean,在子bean中属性指定parent="id"指定父bean,这样子bean就可以继承父bean的配置,如果不想实例化父bean,只当做模板,那么在父bean的属性指定abstract=“true”,也可以不写父bean的class属性,那么abstract就一定指定为true
 
2.4 spring对date类型属性的注入,直接set注入"2015-02-14"会出错,spring提供了两种方法注入http://www.yiibai.com/spring/spring-how-to-pass-a-date-into-bean-property-customdateeditor.html
 
1. 声明一个dateFormat bean,在“customer” Bean,引用 “dateFormat” bean作为一个工厂bean。该工厂方法将调用SimpleDateFormat.parse()自动转换成字符串Date对象。
        <bean id="dateFormat" class="java.text.SimpleDateFormat">
                <constructor-arg value="yyyy-MM-dd" />
        </bean>
//自定义类customer
        <bean id="customer" class="com.yiibai.common.Customer">
                <property name="date">
                        <bean factory-bean="dateFormat" factory-method="parse">
                                <constructor-arg value="2015-12-31" />
                        </bean>
                </property>
        </bean>
 
第二种方法: 
声明一个 CustomDateEditor 类将字符串转换成 java.util.Date。
<bean id="dateEditor"
                class="org.springframework.beans.propertyeditors.CustomDateEditor">
          <!--构造函数表示构造格式和是否为空-->
                <constructor-arg>
                        <bean class="java.text.SimpleDateFormat">
                                <constructor-arg value="yyyy-MM-dd" />
                        </bean>
                </constructor-arg>
                <constructor-arg value="true" />
 
        </bean>
 <!--并声明另一个“CustomEditorConfigurer”,使 Spring转换 bean 属性,其类型为java.util.Date-->
        <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
                <property name="customEditors">
                        <map>
                                <entry key="java.util.Date">
                                        <ref local="dateEditor" />
                                </entry>
                        </map>
                </property>
        </bean>
<!---自定义类->
        <bean id="customer" class="com.yiibai.common.Customer">
                <property name="date" value="2015-12-31" />
        </bean>
 
 
 
2.3 自动装配(不常用,后面有更直观的技术)
SpringIOC不用set注入和构造器注入,一样可以依赖注入,在创建bean时,可以根据类型或者名称,从容器中找到匹配的bean,设置给这个bean属性,在bean中用autowire属性指定装配规则,默认no,可以选择byName byType constructor autodetect(有默认构造器选择constructor,不然选择byType)
实际项目中,可以给一个bean1声明接口,给另一个bean2注入的是这个bean的实现类,若依赖的bean2发生改变,直接更改bean的实现类即可。
IMG_20170306_193229IMG_20170306_193229
2.4springEL表达式
在spring配置文件中,获取其他bean或者集合的值,
1.#{beanid.属性} beanid是容器中bean的id,这个bean必须有get属性的方法,和EL表达式读取bean差不多。
2.如果要读取一个集合中的一个属性,也和EL差不多,#{beanid.listName[index]}
3.读取map集合的一个value,#{beanid.mapN.keyN}
4.读取proeprties的属性值,#{id.propertyName}
5.使用其他bean的方法 #{beanId.method()}
6.支持运算符:+-*%/^
7.springel表达式中+还可以当做字符串连接符 :#{beanid.name+"你好"}
8.支持比较运算符:<<=>>===!= le ge lt gt eq #{beaid.age gt 20}
9.and or not #{shop.isable and shop.name=='shop'} #{not shop.isabel}
10.正则表达式 #{shop.name matches '[a-zA-z]{2,4}'}
11.静态方法 T()方式 #{T(java.lang.Math).random()*10}
2.5spring中的后置处理器:在spring容器中对所有的bean,调用init初始化方法前后的处理,实现BeanPostProcessor接口即可。
public class Proo implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
       if(!s.equals("testt")){
           MyTest o1 = (MyTest) o;
           System.out.println("这是mytest的前置通知");
       }
       return o;
    }
 
    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        if(s.equals("testt")){
            MyTest o1 = (MyTest) o;
            System.out.println("这是mytest的后置通知");
        }
        return o;
    }
}
3方式二:基于注解的配置(不需要set方法了)   注解连线在默认情况下在 Spring 容器中不打开。再spring中配置 <context:annotation-config/> 这个注解激活@PostConstruct   @PreDestroy @AutoWire @Resource等
3.1 组件扫描(使用了<context:component-scan base-package=””/>,就不用再写<context:annotation-config/>,前者包含了后者的功能。)
Spring容器启动之后,扫描配置文件,如果配置文件中有下面的组件扫描,则容器会扫描指定包极其子包下面的类,多个包之间用,分隔 -->如果该类包含了特定的注解,则容器会将这个类纳入容器进行管理(相当于在配置文件中配置了一个bean),默认这个类的id是首字母小写的类名,如果想更改id,在注解后添加(“newId”)
<context:component-scan base-package=””/>
注解标记  
@Component      通用
@Repository   持久层
@Service       业务层 
@Controller   控制层
类的作用域:在类名前加上 @Scope(“prototype”),可以保证线程安全,每次使用都是新的对象
Bean的声明周期: 在init方法前加上注解 @PostConstruct , 在destroy方法前加上  @PreDestroy 这个不属于spring,在xml添加<context:annotatin-config/>启动这个注解,有组件扫描就不用。
延迟加载:加上注解 @Lazy(true)
DI依赖注入:
  1. Autowired默认是bytype方式,可能有多个bean合适,所以在参数中增添@qualifier指定要注入bean的Id按名称注入
方式一:在set方法前添加注解
@Autowired
    public void setWaiter(@Qualifier("wt") Waiter waiter) {
        this.waiter = waiter;}
方式二:也可以在属性前加,这时对应的set方法可以不要
@Autowired
    @Qualifier("wt")
    private Waiter waiter;
方式三:Autowired的构造器注入方式:
@Autowired
    public Hotel(@Qualifier("wt") Waiter waiter){
        System.out.println("hotel的有参构造器");
    }
  1. Resource注入,默认根据byName方式注入,根据属性名或者色图参数里的参数名找bean,找不到就根据属性名前的类型找bean,一般所以后面跟一个name,根据resource指定的name找bean。         用在set方法前或者属性字段前,写在属性名前就不用写setter方法。   
@Resource(name="wt") 这是java中的一个jar包
    public void setWaiter(Waiter waiter) {
    System.out.println("manager的注入方法");
        this.waiter = waiter;
    }
 
@Resource(name="wt")
private Waiter waiter;
使用注解的方式使用spring表达式读取值,写在属性前或者set方法前
@Value("#{id.属性值}")
也可以使用@Value注解给属性赋值,写在属性前或者set方法前
@Value("${name}")  
    private String pageSize;
spring的EL表达式:
 
<import>标签引入其他spring配置文件
 
注意:spring有一个依赖包:commons-logging-1.1.1.jar
 
注意:当类中只有一个参数的构造器,不用显示注入,他会自动注入该bean
@Data
@Component
public class Student {
    private Book book;
    public Student(Book book){
        this.book = book;
    }
}
 
@Data
@Component
public class Book {
    @Value("zhouyang")
    private String name;
}
 
@Resource
private Student student;
@org.junit.Test
public void test(){
    System.out.println(student);
}
这是可以直接注入的。
5.方式三:不是用xml的配置类,为了消除xml配置文件
5.1@Configuration 用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration 注解的类.class)。
@Configuration
public class SpringConfiguration {
}
5.2@ComponentScan 扫描类,作用同<context:component-scan base-package="com.zy"/>
@Configuration
@ComponentScan(("com.zy"))
public class SpringConfiguration {
}
5.3@Bean 该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 spring 容器。没写name属性就默认用方法的名称作为bean的id
@Configuration
@ComponentScan(("com.zy"))
public class SpringConfiguration {
@Bean(name="student")
    public Student student(){
            return new Student();}
}
5.4@PropertySource 用于加载.properties 文件中的配置。通常与@Value一起使用, properties配置文件中的值存储到Spring的 Environment中
@Configuration
@ComponentScan(("com.zy"))
@PropertySource("classPath:db.Properties")
public class SpringConfiguration {
@Vaule("${name})
private string name;
@Bean(name="student")
    public Student student(){
Studnet student = new Student();
student.setName(name);
return student;
           ;}
}
5.5 @PropertySources   功能同@PropertiSource,配置多文件
@PropertySources({
@PropertySource("classpath:config.properties"),
@PropertySource("classpath:db.properties")
})
5.6@Import  用于导入其他配置类或者普通类,在引入其他配置类时,可以不用再写@Configuration 注解。写上也没问题
导入配置类
@Configuration
@ComponentScan(basePackages = "com.itheima.spring")
@Import({ JdbcConfig.class})
public class SpringConfiguration {
}
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig{
}
 
导入普通类,把该类加入容器中
public class TestA(){}
@Configuration
@ComponentScan(basePackages = "com.itheima.spring")
@Import({ JdbcConfig.class})
public class SpringConfiguration {
}
5.7@Profile   指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件; dev test master
    1) 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
    2) 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
    
    @Value("${db.user}")
    private String user;
    
    private String driverClass;
    
    @Profile("default")
    @Bean("test")
    public DataSource testDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }
    
    @Profile("dev")
    @Bean("dev")
    public DataSource devDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }
    
    @Profile("master")
    @Bean("master")
    public DataSource masterDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        String driverClass = resolver.resolveStringValue("${db.driverClass}");
        this.driverClass = driverClass;
    }
}
 
 
public class IOCTestProfile {
    //1. 使用命令行动态参数:在虚拟机参数位置加载 -Dspring.profiles.active=test
    //2. 使用代码的方式激活某种环境;
    @Test
    public void test01() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
        //1. 创建一个applicationContext
        //2. 设置需要激活的环境
        applicationContext.getEnvironment().setActiveProfiles("dev","master");
        //3. 注册主配置类
        applicationContext.register(MainConfigOfProfile.class);
        //4. 启动刷新容器
        applicationContext.refresh();
        
        String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
        System.out.println(Arrays.toString(beanNamesForType));
        
        applicationContext.close();
    }
5.8 @Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。
  1.写在配置类上,表示配置类所有的bean满足条件加入容器
   2.写在@Bean上,该bean满足条件加入容器
 
@Configuration
 
public class BeanConfig {
 
@Bean(name = "bill")
@Conditional({LinuxCondition.class})
public Person person1(){
 
return new Person("Bill Gates",62);
}
//LinuxCondition实现了Condition接口,满足mathes方法返回true,该bean加入容器
public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        String property = environment.getProperty("os.name");
        if (property.contains("Linux")){
            return true;
        }
        return false;
    }}
5.9 @Scope @Lazy登注解写在@Bean这里
5.10 通过注解获取容器
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
5.11 xml和javaconfig相互引用
  •  xml中引入其他xml配置文件  :<import  resource =“classpath:other.xml”>
  • xml引入javaconfig,当做一个bean, <bean id="config" class="Config">
  •     javaconfig中引入xml配置文件 
@Configuration
@ImportResource("classpath:applicationContext.xml")
public class BeanConfig {}
6.spring Junit测试,导入jar包,
@ContextConfiguration 注解:
locations 属性:用于指定配置文件的位置。如果是类路径下,需要用 classpath:表明
classes 属性:用于指定注解的类。当不使用 xml 配置时,需要用此属性指定注解类的位置。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:bean.xml"})
public class AccountServiceTest {
@Resource
private Student student;
}
7.spring依赖检查
 
方式一:xml注册
<bean id="" class="" depends-on="car,student"></bean>
写依赖的beanid,会在当前bean实例化之前创建好,写多个依赖用逗号
方式二:注解检查
在set方法上添加@required注解
在xml中注册  或者添加   <context:annotation-config/>有mvc注解就不需要
posted @ 2020-08-26 12:33  z街角的风铃y  阅读(234)  评论(0)    收藏  举报