Spring
装配Bean
自动装配
@Component/@Named:
- 作用:声明是组件
- 为bean设置ID:@Component(“beanName”)
@ComponentScan:
- 作用:扫描组件
设置扫描的基础包:
@ComponentScan(basePackages ={"packageName","packageName"}) @Configuration public class config{}
@ComponentScan(basePackageClasses ={ClassName1.class,ClassName2.class}) @Configuration public class config{}
@Autowried/@Inject:
可以用到任何方法上,都会满足方法参数上的依赖
- @Autowried(required = false):如果没有装配bean则不会进行注入,但是该属性会是null,需要在代码上进行空指针的处理
通过Java代码装配bean
@Configuration:
作用声明配置类
@Configuration public Class javaConfig{ }
@Bean:
- 在方法上注解,该方法会创建该Bean的实例,返回实例的接口
@Bean public InterfaceName funcationName(){ return new Implement(); }
- 给Bean设置ID
@Bean(name="beanId") public InterfaceName funcationName(){ return new Implement(); }
注入
@Bean public CompactDisc sgtPeppers(){ return new SgtPeppers(); } 1. @Bean public CDplayer cdPlayer(){ return new CDplayer(sgtPeppers());} 2. @Bean public CDplayer cdPlayer(){ return new Cdplayer(CompactDisc compactDisc)}
通过XML装配bean
- 创建xml规范
声明Bean:
这种方式声明的Bean的id可能为完全限定名#0
<bean class="完全限定名"/>
设置id:
<bean class="完全限定名" id="id"/>
注意这里面我们并不会去检查完全限定名的合法性
构造器注入bean
使用bean的id注入Bean
<bean id="cdPlayer" class="soundsystem.CDPlayer"> <constructor-arg ref="compactDisc"/> </bean>
使用字面量注入
<bean id="compactDisc" class="soundsystem.BlankDisc"> <constructor-arg value="Sgt. Pepper`s Lonly Hearts Club Band"/> </bean>
使用<list><set>元素,注入
<bean id="" class=""> <constructor-arg> <list> <ref bean=""/> <ref bean=""/> </list> </constructor-arg> </bean>
<bean id="" class=""> <constructor-arg> <set> <value>Sgt. Pepper`s Lonly Hearts Club Band</value> <value>Sgt. Pepper`s Lonly Hearts Club Band</value> </list> </constructor-arg> </bean>
使用setter方法注入
使用bean的id注入
<bean id="" class=""> <property name="" ref="compactDisc"/> </bean>
使用字面量注入
<bean id="" class=""> <property name="" value="Sgt. Pepper`s Lonly Hearts Club Band"/> <property name=""> <list> <value>Sgt. Pepper`s Lonly Hearts Club Band</value> </list> </property> </bean>
- 使用util-命名空间中的部分成员
混合配置
Java配置混合Java配置和XML配置
Java配置混合Java配置
@Configuration public class CDConfig{ @Bean public CompactDisc compactDisc(){ return new SgtPeppers(); } } @Configuration @Import(CDConfig.class) public class CDPlayerConfig{ @Bean public CDPlayer cdPlayer(CompactDisc compactDisc){ return new CdPlaerImpl(compactDisc); } }
Java配置混合XML配置
<bean id="compactDisc" class="soundsystem.BlankDisc"/> @Configuration @ImportResource("classpath:cd-config.xml") public class CDPlayerConfig{ @Bean public CDPlayer cdPlayer(CompactDisc compactDisc){ return new CdPlaerImpl(compactDisc); } }
XML配置混合Java配置和XML配置
XML配置混合XML配置
<bean id="compactDisc" class="soundsystem.BlankDisc"/> <import resource="cdplayer-config.xml"/>
XML配置混合Java配置
<bean id="compactDisc" class="soundsystem.BlankDisc"/> <bean class="soundsystem.CDConfig"/>
高级装配
注入Bean的条件控制
环境控制profile
Java配置的环境控制使用@Profile
@Configuration public class DataSourceConfig{ @Bean @Profile("dev") public DataSource embeddedDataSource(){ return new DataSourceImpl1(); } @Bean @Profile("prod") public DataSource embeddedDataSource(){ return new DataSourceImpl2(); } }
XML配置的环境控制使用<beans>元素的profile属性
<beans profile="dev"> <bean id="dataSource" class="DataSourceImpl1"></bean> </beans> <beans profile="prod"> <bean id="dataSource" class="DataSourceImp21"></bean> </beans>
激活profile
到底激活哪个profile依赖两个属性
- spring.profiles.active
- spring.profiles.default
- 两个属性都设置了,则看active这个属性;如果两个都没有设置,则spring只会创建没有定义profile的Bean
设置属性的方式
作为DispatcherServlet的初始化参数
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/root-context.xml</param-value> </context-param> <context-param> <param-name>spring.profiles.default</param-name> <param-value>dev</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>spring.profiles.default</param-name> <param-value>dev</param-value> </init-param> </servlet>
- 作为web应用的上下文参数
- 作为JNDI条目
- 作为JVM的系统属性
在集成测试类上,使用@ActiveProfiles注解设置
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes={PersistenceTestConfig.class}) @ActiveProfiles("dev") public class PersistenceTest{}
@Conditional
@Bean @Conditional(MagicExistsCondition.class) public MagicBean magicBean(){ return new MagicBean(); } 需要实现接口condition public class MagicExistsCondition implements Condition{ public boolean matchs(ConditionContext context, AnnotatedTypeMetadata metadata) { Environment env = context.getEnvironment(); return env.containsProperty("magic"); } }
spring4中@Profile @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) @Documented @Conditional(ProfileCondition.class) public @interface Profile{ String[] value(); }
处理装配Bean的歧义性
当有很多个相同接口实现的Bean的时候,spring进行注入,不知道该如何选择
使用@Primary标示首选的Bean,将会使用首选的Bean
@Component @Primary public class IceCream implements Desser{} @Bean @Primaryy public Dessert iceCream(){ return new IceCream(); } <bean id="iceCream" Class="IceCream" primary="true"/>
不能对多个Bean进行首选
使用@Qualifier限定自动装配的Bean
@Autowired @Qualifier("iceCream") public void setDessert(Dessert dessert){ this.dessert = dessert; }
@Qualifier里面的值就是限定符,一般使用@Component注解声明的类创建的Bean的id就是首字母小写的类名,而没有注明限定符的Bean,它的限定符就是id
如果后面重构了这个Bean的类名,那么后面将会注入失败,所以我们应该创建自定义的限定符
自定义限定符
@Component
@Qualifier("iceCream")
public class IceCream implements Desser{}
@Autowired
@Qualifier("iceCream")
public void setDessert(Dessert dessert){
this.dessert = dessert;
}
2.
@Bean
@Qualifier("iceCream")
public Dessert IceCream(){
return new IceCream();
}
```
2. 使用自定义的限定符注解
```java
@Target({ElementType.CONSTRUCTOR,Element.FIELD,ElementTeyp.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold{}
@Component
@Cold
public class IceCream implements Desser{}
@Autowired
@Cold
public void setDessert(Dessert dessert){
this.dessert = dessert;
}
```
Bean的作用域
分类:
- 单例:整个应用,只会创建一个Bean
- 原型:每次注入Bean都会创建一个Bean
- 会话:在web应用每一个会话创建一个Bean
- 请求:在web应用每一个请求创建一个Bean
- 单例:
默认的作用域
原型:
@Component @Score(ConfigurableBeanFactory.SROPE_PROTORYPE) public class Notepad{}
@Bean @Score(ConfigurableBeanFactory.SROPE_PROTORYPE) public Notepad notepad(){ return new Notepad(); }
<bean in="notepad" class="com.myapp.Notepad" scope="prototype" />
会话/请求:
接口
@Component @Scope( value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES) public ShoppingCart cart(){}
实现类
@Component @Score( value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.TARGET_CLASS) public class ShoppingCartImpl{}
运行时值注入
分类:
使用Environment来注入
- 属性占位符
- spring表达式语言
Enviroment
@Configuaration
@PropertySource("classpath:/com/soundysystem/app.properties") //声明属性源
publci class ExpresssiveConfig{
@Autowired
Environment env;
@Bean
public BlankDisc disc(){
return new BlankDisc(env.getProperty("disc.title"),
evn.getProperty("disc.artist"));
}
}
2. Environement的其他用法
1. 获取属性值
1. String getProperty(String key);
2. String getProperty(String key);
3. T getProperty(String key, Class<T> type);
4. T getProperty(String key, Class<T> type, T defaultVlaue);
2. 检验是否存在
boolean containsProperty(String key);
3. 将属性解析为类
T getPropertyAsClass(String key, CompactDisc.class);
4. 检查profile处于激活状态
String[] getActiveProfiles();返回激活profile名称的数组
String[] getDefaultProfiles();返回默认profile名称的数组
boolean acceptsProfiles(String ... proflies);如果environment支持给定profile的话,就返回true
属性占位符
- xml
<context:propertyplaceholder/>声明使用占位符值注入 <bean id="sgtPepperts" class="sourdsystem.BlankDisc" c:_title="${disc.title}" c:_artist="${disc.artst}" />
- Java
publci BlankDisc( @Value("${disc.title}" title) ) { this.title = tile; } //声明使用属性值注入 @Bean public static PropertySourcesPlaceholderConfigurer placeholderConfigurer(){ return new PropertySourcesPlaceholderConfigurer(); }
AOP
AOP术语
通知:定义切面在什么时候和做什么工作
- 前置通知
- 后置通知
- 返回通知
- 异常通知
- 环绕通知
- 切点:定义何处
- 切面:通知和切点
- 引入:在现有的类不添加新的方法,给类添加新的方法或者属性
织入:把切面应用到目标对象创建的代理对象的过程。织入的时间点有以下
- 编译期:需要特殊的编译器
- 类加载期:目标类加载到JVM时,需要特殊的类加载器。
- 运行期:
分类
- 基于代理的经典Spring AOP
- 纯POJO切面
- @AspectJ注解驱动的切面
- 注入式AspectJ切面
基于动态代理,仅支持方法连接点,不支持字段和构造器的接入点
通过切点来选择连接点
AspectJ指示器 | 描述 |
---|---|
execution | 用于匹配是连接点执行的方法 |
arg() | 限制连接点匹配参数为指定类型的执行方法 |
this() | 限制连接点匹配AOP代理的Bean引用为指定类型的类 |
target | 限制连接点匹配目标对象为指定类型的类 |
within() | 限制连接点匹配指定的类型 |
@annotation | 限定匹配带有指定注解的连接点 |
使用AOP的方法
package concert;
public interface Performance{
public void perform();
}
使用使用的触发条件
execution(* concert.Performance.perform(...))
- *代码不在意返回的方法类型
- concert.Performance.perform()代表选择的方法
- perform(..)其中的..代表不在意入参
execution(* concert.Performance.perform(...) && within(concert.*))
- 指定匹配的包是concert
- &&(and)代表与的关系。
- ||(or)代码或的关系
- !(not)代表非的关系
execution(* concert.Performance.perform() and bean('woodstock')) 指定Bean execution(* concert.Performance.perform() and !bean('woodstock')) 指定除了的Bean
使用注解创建切面
@Aspect
public class Audience{
@Before("execution(** concert.Performance.perform(..)")
public void silenceCellPhones(){
System.out.println("Silencing cell phones");
}
@Before("execution(** concert.Performance.perform(..))")
public void takeSeats(){
System.out.println("Taking seats");
}
@AfterReturning("execution(** concert.Performance.perform(..))")
public void applause(){
System.out.println("CLAP CLAP CLAP!!!");
}
@AfterThrowing("execution(** concert.Performance.perform(..))")
public void demandRefund(){
System.out.println("Demanding a refund");
}
}
spring 使用AspectJ注解来声明通知方法
注解 | 通知 |
---|---|
@After | 通知方法会在目标方法返回或抛出异常后调用 |
@AfterReturning | 通知方法会在目标方法返回后调用 |
@AfterThrowing | 通知方法会在目标方法抛出异常后调用 |
@Around | 通知方法会将目标方法封装起来 |
@Before | 通知方法会在目标方法调用之前执行 |
使用@Poincut定义可重用的切点
@Aspect
public class Audience{
@Pointcut("execution(** concert.Performance.perform(..")
public void performance(){}
@Before("performance()")
public void silenceCellPhones(){
System.out.println("Silencing cell phones");
}
@Before("performance()")
public void takeSeats(){
System.out.println("Taking seats");
}
@AfterReturning("performance()")
public void applause(){
System.out.println("CLAP CLAP CLAP!!!");
}
@AfterThrowing("performance()")
public void demandRefund(){
System.out.println("Demanding a refund");
}
}
启动自动代理功能
使用Java配置
@Configuration @EnableAspectJAutoProxy @ComponentScan public class ConcertConfig {}
使用XML配置
<aop:aspectj-autoproxy />