Spring学习

3 篇文章 0 订阅
2 篇文章 0 订阅

Spring DI

Spring容器

Spring容器负责创建、装配、配置对象并管理对象的整个生命周期,从生存到死亡(new —> finalize)。
Spring容器有多种实现方式,总体可归纳为两类:
1. bean工厂:最简单的容器,提供基本的DI支持
2. 应用上下文:给予bean工厂构建,提供应用框架级别的服务
1. AnnotationConfigApplicationContext:基于java的配置类加载Spring应用的上下文
2. AnnotationConfigWebApplicationContext:基于java的配置文件加载SpringWeb应用的上下文
3. ClassPathXmlApplicationContext:从xml文件中加载上下文(xml文件是应用的资源文件)
4. FileSystemXmlApplicationContext:从文件系统中的xml中加载上下文
5. XmlWebApplicationContext:从Web应用下的xml文件中加载上下文

ApplicationContext cnt = new FileSystemXmlApplicationContext("c:/contxt.xml");

ApplicationContext cnt = new ClassPathXmlApplicationContext("context.xml");

ApplicationContext cnt = new AnnotationConfigApplicationContext(package.to.config.Java.class);

应用的上下文准备就绪之后,就可以调用上下文的getBean()方法从Spring容器中获取所需的Bean

bean的生命周期

传统java应用中,使用关键字new完成bean的实例化,然后改bean就可以被使用。一旦该bean不再被使用时,JVM会自动回收。
而Spring容器中Bean的生命周期则复杂得多:
1. 实例化
2. 填充属性
3. 调用BeanNameAware的setBeanName方法;
4. 调用BeanFactoryAware的setBeanFactory方法;
5. 调用ApplicationContextAware的setApplicationContext方法;
6. 调用BeanPostProcessor的预初始化方法;
7. 调用InitializeingBean的afterPropertiesSet方法
8. 调用自定义的初始化方法
9. 调用BeanPostProcessor的初始化后方法
10. bean被应用使用
11. spring容器被关闭
12. 调用DisposableBean的destory方法
13. 调用自定义的销毁方法

装配Bean

Spring提供了三种装配bean的方式:
(1)利用xml文件进行显示装配 (2)在java文件中进行显示装配 (3)利用注解进行隐式自动化装配

自动化装配Bean

Spring从两个角度来实现自动化装配:1. 组件扫描 2. 自动装配
1. 创建可被发现的bean

一般会定义接口,并在接口的实现类上修饰Component注解(也可用Named注解)

2. 可对bean进行命名

在修饰bean的Component注解指定bean的名称: @Component("bean_name")
  1. 注入bean

    在某个bean的某个 字段方法构造 方法上,用Autowired注解修饰

  2. 启动组件扫描,设置组件扫描的基础包

    创建Config配置类,并用Configuration和ComponentScan注解修饰该类

    @Component("package")
    @Component(basePackages={"package1","package2","package3"})
    @Component(basePackageClasses={Bean1.class,Bean2.class,Bean3.class})//此时会分别扫描这三个类所在的包
    

    也可以通过xml文件来启动组件扫描

通过JavaConfig文件进行显示装配

当遇到需要将第三方库中的组件装配到自己的应用中的时候,自动化装配方法就行不通,这时候需要使用Java文件或者XML文件进行显示装配
1. 创建配置类

在利用Configuration注解修饰配置类

2. 在配置类中声明Bean

利用Bean注解

以下是一个简单的利用java配置文件进行显示装配的例子:


public class JavaConfig{

    @Bean
    public Bean1 createBean1(){
        return new Bean1();
    }

    @Bean
    public Bean2 createBean2(){
        Bean1 bean1 = new Bean1();//Spring会对此进行拦截,这里生成的bean1其实和上面方法成的是同一个对象
        Bean2 bean2 = new Bean2(bean1);
        return bean2;
    }
}

通过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-3.0.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd">

      <bean id="bean0" class="package.to.bean0"/>

     <bean id="bean1" class="package.to.bean1">
        <property name="field1" ref="bean0" />
        <property name="field2" value="Tom" />
     </bean>

     <bean id="bean2" class="package.to.bean2">
        <constructor-arg ref="bean1"/>
        <constructor-arg>
            <list>
                <value>value1</value>
                <value>value2</value>
            </list>
        </constructor-arg>
     </bean>

  </beans>

混合配置

在一个项目中,完全可以同时存在以上三种配置
1. 在JavaConfig配置文件中引用另外一个JavaConfig配置wenjian


@Configuration
@Import({AnotherJavaConfig1.class,AnotherJavaConfig2.class})
public class JavaConfig{

    @Bean
    public Bean createBean(){return new Bean();}

}
  1. 在JavaConfig文件中引入XML配置文件

@Configuration
@ImportResource("classpath:config.xml")
public class JavaConfig{

    @Bean
    public Bean createBean(){return new Bean();}

}
  1. 在XML文件中引入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-3.0.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd">

      <bean id="bean0" class="package.to.bean0"/>

     <import resource = "anotherXMLConfig.xml"/>

  </beans>
  1. 在XML文件中引入JavaConfig配置
<?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-3.0.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd">

      <bean id="bean0" class="package.to.bean0"/>

    <bean class="package.to.JavaConfig"/>

  </beans>

Spring高级装配

Profile

Spring在构建的时候保留所有信息,在运行时根据环境决定哪些bean应该被创建。因此,一份构建好的单元可以被部署到不同的环境。 \
Spring通过spring.profiles.active和spring.profiles.default属性值来确定被激活的Profile。spring.profiles.active属性值优先,如果其值没有被设定的话,则依据spring.profiles.default的值。如果两个都没有被设定的话,则只会创建没有被Profile注解修饰的Bean

@Configuration
public class JavaConfig{

    @Bean
    @Profile("prd")  //只在prd环境才会被创建
    public Bean createBean(){return new Bean();}

    @Bean
    @Profile("dev")  //只在dev环境才会被创建
    public Bean1 createBean1(){return new Bean1();}

    @Bean  //任何环境都会被创建
    public Bean2 createBean2(){return new Bean2();}

}
<?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-3.0.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd">

     <beans profile="dev">
        <bean id="bean0" class="package.to.bean0"/>
     </beans>

  </beans>
条件化的Bean

依据条件来决定是否创建Bean

@Bean
@Conditional(MagicExistsCondition.class)
public Bean createBean(){return new Bean();}
public class MagicExistsCondition implements Condition{
    public boolean matches(ConditionContext context,AnnotatedTypeMetadata metedata){
        Environment env = context.getEnvironment();
        return env.containsProperty("magic");
    }
}
自动装配的歧义性
Primary注解

当有两个或更多的Bean可以被同时注入到属性或者方法中时,Spring做出选择到底装配哪一个,会抛出NoUniqueBeanDefinitionException异常。此时,可以在其中的某个Bean上使用@Primary注解修饰。Spring会优先选择被Primary注解修饰的Bean用来注入。

限定自动装配的Bean
运行时注入

在上面的JavaConfig/XML文件中,我们通过硬编码的方式注入了某些值。但是有时候我们希望在运行时再确定这些值。可以通过以下两种方法:(1)属性占位符 (2)Spring表达式语言

注入外部值
@Configuration
@PropertySource("classpath:app.properties")
public class JavaConfig{

    @Autowired
    Environment env;

    @Bean
    public Bean1 createBean1(){

        return new Bean1(
            env.getProperty("user.name"),
            env.getProperty("user.age")
        );

    }

}
 /*app.properties文件中定义了值和属性,内容如下:
    user.name = Tom
    user.age = 19
这些值会被加载到Environment中,所以可以从中进行检索
 */
属性占位符

在使用属性占位符的时候,必须配置一个PropertyPlaceholderConfigurer Bean或者PropertySourcesPlaceholderConfigurer Bean。

@Configuration
@PropertySource("classpath:app.properties")
public class JavaConfig{

    @Autowired
    Environment env;

    @Bean
    public Bean1 createBean1(@Value("${user.name}")String userName,
        @Value("${user.age}")int userAge){
        return new Bean1(userName,userAge);
    }

}

<bean id="bean1" class="package.to.Bean1" c:_name="${user.name}" c:_age="${user.aget}"/>
Spring表达式语言
Spring表达式语言的形式为:#{......}

Bean的作用域

  1. 单例(Singleton):整个应用中,某类的bean只创建一个实例
  2. 原型(Prototype):每次注入或者每次从Spring的上下文中获取的时候,都会生成一个新的bean
  3. 会话(Session):在Web应用中,为每个会话创建一个bean实例
  4. 请求(Request):在Web应用中,为每个请求创建一个bean实例

    spring中,bean默认是为单例的

//自动扫描与隐式装配
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Bean{}

//显示装配
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Bean1 createBean1(){return new Bean1();}

//xml中
<bean id="bean1" class="package.to.Bean1" scope="prototype"/>

Spring AOP

术语

  1. 通知
  2. 连接点
  3. 切点
  4. 切面

假设我们在某个方法调用的时候,需要在其调用之前进行权限校验,在方法调用之后进行日志记录。则该方法可以被称为连接点,权限校验和日志记录称为前置通知和后置通知,切点定义了通知被具体应用的位置,通知和切点组成切面。

Spring对AOP的支持

  1. Spring通知是基于java编写的
  2. Spring在运行时通知对象

    代理对象包裹目标对象,当代理对象拦截到对目标对象的方法调用时,会在目标对象的方法被调用之前先调用切面逻辑。由于Spring在运行时才会创建代理对象,因此不需要特殊的编译器。

  3. Spring只支持方法级别的连接点

Spring AOP的使用

编写切点

//该切点会匹配com包下的Performace类的perform方法,
//无论该方法的参数与返回值类型
execution(* com.Performance.perform(..))

execution(* com.Performace.perform(..)) and within(com.*)

在切点中选择Bean

//在上面的条件上,再次限定bean的id
execution(* com.Performance.perform(..)) and bean("my_bean_name")

使用注解创建切面

@Aspect
public class MyAspect{

    //连接点方法调用之前被调用
    @Before("execution(* com.Performance.perform(..))")
    public befreMethodInvoke(){

    }
    //连接点方法返回之后被调用
     @AfterReturning("execution(* com.Performance.perform(..))")
    public afterMethodInvoke(){
    }

    //连接点方法抛出错误之后被调用
    @AfterThrowing("execution(* com.Performance.perform(..))")
    public afterMethodInvokeThrowException(){

    }
    //连接点方法抛出错误之后被调用,或者连接点方法正常返回之后被调用
    @After("execution(* com.Performance.perform(..))")
    public afterMethodInvoke(){

    }

}

启动AOP

MyAspect 必须要被容器实例化为bean
在JavaConfig中利用EnableAspectJAutoProxy / 在xml文件中声明
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值