java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring中的IOC和AOP

Spring中IOC和AOP的核心组成架构详解

作者:抠脚的大灰狼

这篇文章主要介绍了Spring中IOC和AOP的核心组成架构详解,本文是对Spring的2大核心功能——IoC和AOP 的总结提炼,并增加了环境profile和条件化bean的内容,篇幅较短,更像是一个大纲,或者思维导图,需要的朋友可以参考下

IoC配置

注册bean

XML

<bean> 标签

属性

子标签

注解

其他注解

装配bean

@Autowired

属于Spring,按类型注入, required 属性默认为 true 。由Spring中的 AutowiredAnnotationBeanPostProcessor 进行处理。

注:带 @Autowired 注解的方法,会被Spring自动调用。

@Resource

属于JavaEE(JSR250),当指定了 name 属性时,按照名称( bean 的 id )注入;否则,按照类型注入

@Inject

属于JavaEE(JSR330),需导入额外的 jar 包,按照类型注入

<dependency>
   <groupId>javax.inject</groupId>
   <artifactId>javax.inject</artifactId>
   <version>1</version>
</dependency>

@Value

用来注入基本类型和 String 类型的值。

可以用 ${} ,来获取 properties 文件中的属性。( properties 文件要加载到Spring中)

关于把 properties 文件加载到Spring

可通过 <context:property-placeholder> 标签进行简化

用 @PropertySource 结合 @Component 或者 @Configuration

注意: properties 文件中的属性,会被加载到Spring的Environment对象中,多个 properties 中的同名属性,会发生覆盖

高级装配

环境与Profile

@Profile 与 @Configuration 或 @Component , @Bean 等结合使用。

可以控制仅在某一 profile 下激活对应的类。如下面的配置类仅在 dev 环境下生效

@Profile("dev")
@Configuration
public class DevConfig {
    @Bean
    public PetService petService() {
        return new PetService();
    }
}

如何指定当前激活的 profile ?

依赖于2个独立属性: spring.profiles.active 和 spring.profiles.default 。

若设置前者,则根据前者来确定;若没设置前者,则根据后者来确定。若2者都未指定,则只会激活那些没有定义在某一 profile 下的类

有多种方式来设置这2个属性

<profiles>
        <!-- 开发环境 -->
        <profile>
            <id>dev</id>
            <properties>
                <spring.profiles.active>dev</spring.profiles.active>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <!-- 生产环境 -->
        <profile>
            <id>prod</id>
            <properties>
                <spring.profiles.active>prod</spring.profiles.active>
            </properties>
        </profile>
    </profiles>
<!-- web,xml 中 -->
<!-- 省略其他部分 -->
<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>dev</param-value>
</context-param>

作为DispatcherServlet的启动参数(SpringMvc)

条件化bean

在满足某些条件时,才创建某些 bean 。通过 @Conditional 注解和 Condition 接口实现,示例如下

package org.demo.pet.conditional;
public class MagicBean { }
package org.demo.pet.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class MagicCondition implements Condition {
	/**
	 * 若 matches 方法返回 true, 则表示条件满足, 会创建对应的bean; 若返回 false, 则不会创建对应bean
	 * **/
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 当Spring的Environment中存在名为 magic 的属性, 才认为满足条件
		return context.getEnvironment().containsProperty("magic");
	}
}
package org.demo.pet.conditional;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConditionalConfig {
	@Conditional(MagicCondition.class)
	@Bean
	public MagicBean magicBean() {
		return new MagicBean();
	}
}

测试

package org.demo.test.condition;
import org.demo.pet.conditional.ConditionalConfig;
import org.demo.pet.conditional.MagicBean;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ConditionalConfig.class)
public class ConditionTest {
	@Autowired(required = false)
	private MagicBean magicBean;
	@Test
	public void test() {
		System.out.println(magicBean == null);
	}
}

由于 magic 属性在Spring中不存在,所以上面的 magicBean == null 表达式值为 true ,如下

若添加 magic 属性,则 MagicBean 会被创建

# magic.properties
magic=HarryPotter
package org.demo.pet.conditional;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:magic.properties")
public class ConditionalConfig {
	@Conditional(MagicCondition.class)
	@Bean
	public MagicBean magicBean() {
		return new MagicBean();
	}
}

再次运行测试, magicBean == null 表达式值为 false

Condition 接口中的 matches 方法提供了2个参数: ConditionContext 和 AnnotatedTypedMetadata

通过 ConditionContext

通过 AnnotatedTypedMetadata ,可以检查注解的情况

Spring自带的的 @Profile 注解,也是通过 @Conditional 这种方式实现的

处理歧义性

依赖注入时,当同一个类型,有多个候选 bean 时,如何解决?

使用 @Primary 注解( @Primary 与 @Component 搭配,或 @Primary 与 @Bean 搭配)(只能有一个首选 bean ,当出现多个首选 bean 时,Spring仍然不知道该注入哪一个)

@Qualifier 是主要的限定符使用方式,可以搭配 @Autowired ,或者 @Inject 。

一个 bean 的限定符,默认情况下是这个 bean 的 id ;当然,也可以为 bean 设置自定义的限定符,如

@Component
@Qualifier("cold")  // 也可以与@Bean注解结合使用
public class IceCream implements Dessert {
}

一个 bean 可以有多个限定符,不同的 bean 可以有相同的限定符。当依赖注入时,如果通过一个限定符仍然能匹配多个候选者,那么可以指定更多的限定符,如

@Component
@Qualifier("cold")
@Qualifier("creamy")
public class IceCream implements Dessert {
}
@Component
@Qualifier("cold")
public class Popsicle implements Dessert {
}
@Autowired
@Qualifier("cold")
@Qualifier("creamy")
public void setDessert(Dessert dessert) {}

注:Java 8 之前不允许出现重复注解,Java 8以后,当这个注解被标记为 @Repeatable 时,可以重复。

可以创建自定义的限定符注解来解决这个问题,如

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold {
}
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Creamy {
}

AOP配置

术语

使用 XML

<aop:config>
        <aop:pointcut id="pointcut" expression="within(org..*.PetService)"/>  <!-- 切入点 -->
        <aop:aspect ref="xmlAspect"> <!-- 切面, 使用id为xmlAspect的对象 -->
            <aop:before method="log" pointcut-ref="pointcut"/>  <!-- 使用切面对象中的log方法, 对切入点应用前置通知 -->
        </aop:aspect>
</aop:config>

注解

切入点

切入点表达式

切入点表达式中可以用通配符和逻辑运算符

通配符

逻辑运算符: && , || , ! (在XML中需要换成 and , or , not )

通知

环绕通知,最强大的通知。其方法形参中必须包含一个 ProceedingJoinPoint 对象,可以通过这个对象上的 getArgs 方法获取被拦截的目标对象的方法入参,通过 proceed 方法执行原目标对象的方法。

@EnableAspectJAutoProxy 或者 <aop:aspectj-autoproxy/>

事务支持

3大核心接口:PlatformTransactionManager,TransactionDefinition,TransactionStatus

需要

通常使用Mybatis时,采用spring-jdbc包下的DataSourceTransactionManager即可

使用

XML

注解

@EnableTransactionManagement或者<tx:annotation-driven>

到此这篇关于Spring中核心功能IOC和AOP的详细解读的文章就介绍到这了,更多相关Spring中的IOC和AOP内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文