您的位置:首页 > 编程语言 > Java开发

Spring基于xml配置与注解驱动开发(一)

2018-03-31 13:41 701 查看


spring应用上下文配置

基于xml配置

web.xml

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>


spring-context.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.xsd ">

</beans>


基于注解的配置

web.xml

<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.yt.MainConfig</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>


MainConfig.java

@Configuration
public class MainConfig {

}


bean定义

基于XML的配置,你可以在<bean/>元素通过class属性来指定对象的类型。这个class属性,实际上是BeanDefinition实例中的一个Class属性。IOC容器会通过反射调用构造方法或工厂方法来创建bean

基于xml配置

bean创建

spring-context.xml

<!--通过构造器创建bean-->
<bean id="person" class="com.yt.model.Person"/>
<!--静态工厂方法创建bean-->
<bean id="person1" class="com.yt.factory.PersonFactory" factory-method="newInstance"/>
<!--工厂方法创建bean-->
<bean id="personFactory" class="com.yt.factory.PersonFactory"/>
<bean id="person2" factory-bean="personFactory" factory-method="createInstance"/>


工厂类:

public class PersonFactory {

public static Person newInstance(){
return new Person();
}
public  Person createInstance() {
return new Person();
}
}


依赖注入DI

构造器注入

<!--如果constructor-arg的顺序与构造器参数的顺序不同则需要用注释的三种方式之一来显式的指定构造器参数-->
<bean id="human" class="com.yt.model.Human">
<constructor-arg >
<value>yt</value>
</constructor-arg>
<constructor-arg value="24"/>
<constructor-arg>
<ref bean="person1"/>
</constructor-arg>
<!-- <constructor-arg index="0" value="yt"/>
<constructor-arg index="1" value="24"/>
<constructor-arg index="2" ref="person1"/>-->

<!--<constructor-arg name="name" value="yt"/>
<constructor-arg name="age" value="24"/>
<constructor-arg name="person" ref="person1"/>-->

<!--<constructor-arg type="java.lang.String" value="yt"/>
<constructor-arg type="int" value="24"/>
<constructor-arg type="com.yt.model.Person" ref="person1"/>-->
</bean>


setter注入(必须要有无参构造器和setter方法)

<bean id="human1" class="com.yt.model.Human">
<property name="name" value="yt"/>
<property name="age" >
<value>24</value>
</property>
<property name="person">
<ref bean="person1"/>
</property>
</bean>


工厂方法注入

工厂类:

public static Human newHuman(String name,int age,Person person){
return new Human(name,age,person);
}
public Human createHuman(String name,int age,Person person) {
return new Human(name,age,person);
}


<!--静态工厂方法-->
<bean id="human2" class="com.yt.factory.PersonFactory" factory-method="newHuman">
<constructor-arg value="yt"/>
<constructor-arg value="24"/>
<constructor-arg ref="person1"/>
</bean>
<!--工厂方法-->
<bean id="human3" factory-bean="personFactory" factory-method="createHuman">
<constructor-arg value="yt"/>
<constructor-arg value="24"/>
<constructor-arg ref="person1"/>
</bean>


补充内容

<idref>元素

idref元素用来将容器内其他bean的id(值是字符串-不是引用)传给元素<constructor-arg/> 或者<property/>,如:

property name="name" >
<idref bean="person"/>
</property>

等同于

property name="name" value="person">


通过这种方式可以检验容器中bean是否存在

内部bean

<bean id="human" class="com.yt.model.Human">
<constructor-arg >
<value>yt</value>
</constructor-arg>
<constructor-arg value="24"/>
<constructor-arg>
<bean class="com.yt.model.Person"></bean>
</constructor-arg>
</bean>


内部bean不可以被外部bean引用,同时内部bean是匿名的,不需要id或name属性,IOC容器会忽略这些属性。

NULL

spring会把 “” 作为空字符串处理,对于null spring提供了<null>元素

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


p命名空间

<bean id="human4" class="com.yt.model.Human" p:name="yt" p:age="24" p:person-ref="person1"/>


c命名空间

<bean id="human5" class="com.yt.model.Human" c:name="yt" c:age="24" c:person-ref="person1"/>
<bean id="human6" class="com.yt.model.Human" c:_0="yt" c:_1="24" c:_2-ref="person1"/>


depends-on

bean初始化之前显式地强制一个或多个bean被初始化

<bean id="human6" class="com.yt.model.Human" c:_0="yt" c:_1="24" c:_2-ref="person1" depends-on="person1,person2"/>


延迟初始化bean

<bean id="person" class="com.yt.model.Person" lazy-init="true"/>


ApplicationContext容器在启动时会实例化所有的单例bean,lazy-init 属性默认是false,设置lazy-init=true将不会在ApplicationContext启动时提前实例化,当person是其他单例bean的依赖时,即使lazy-init=true,person依然会被强制加载。

//可以设置全局的单例为lazy
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>


自动装配

mode描述
no(默认)不自动装配。Bean的引用必须用ref元素定义。对于较大的部署不建议改变默认设置,因为明确指定协作者能更好控制和维护系统。 在某种程度上,它记录了系统的结构。
byName通过属性名称自动装配。Spring会寻找相同名称的bean并将其与属性自动装配。譬如,如果bean的定义设置了根据名称自动装配, 并且包含了一个master 属性(换句话说,它有setMaster(..)方法),Spring会寻找名为master的bean的定义,并用它来装配属性
byType如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,将会抛出异常,并指出 不能使用byType自动装配这个bean。如果没有找到相同类型的,什么也不会发生。属性不会被设置。
constructor和byType类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,就会抛出异常。
<bean id="human7" class="com.yt.model.Human" autowire="byName"/>


同样可以设置全局的bean自动装配

<beans default-autowire="byName">
<!-- no beans will be pre-instantiated... -->
</beans>


bean作用域

scope描述
singleton(默认的) 每个 String IoC 容器作用域中一个 bean 定义只对应一个对象实例。
prototype一个 bean 定义对应多个对象实例。
request一个 bean 定义作用于 HTTP request 生命周期;是指每个 HTTP request 拥有自己的通过一个 bean 定义创建的实例。仅在基于 web 的 Spring ApplicationContext 中有效。
session一个 bean 定义作用于 HTTP session 生命周期。仅在基于 web 的 Spring ApplicationContext 中有效。
global session一个 bean 定义作用于全局的 HTTP session 生命周期。仅在 portlet context 中使用才有效。仅在基于 web 的 Spring ApplicationContext 中有效。
application一个 bean 定义作用于整个 ServletContext 生命周期。仅在基于 web 的 Spring ApplicationContext 中有效。
<bean id="human7" class="com.yt.model.Human" autowire="byName" scope="prototype"/>


基于注解的配置

注册组件

包扫描@ComponentScan

/**
* FilterType.ANNOTATION:按照注解
* FilterType.ASSIGNABLE_TYPE:按照指定的类型
* FilterType.ASPECTJ:使用ASPECTJ表达式
* FilterType.REGEX:使用正则表达式
* FilterType.CUSTOM:自定义FilterType,实现TypeFilter接口
*/
//ConponentScan可定义多个
@ComponentScan(value = "com.yt.*",
includeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = Person.class),
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Component.class,Service.class}),
},
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = User.class),
@ComponentScan.Filter(type = FilterType.CUSTOM,classes = MyTypeFilter.class)},
lazyInit = false,
useDefaultFilters = false)//但useDefaultFilters=true时,默认会扫描所有组件@Controller、@Srevice、@Component、@Respository
public class MainConfig {
}


自定义TypeFilter

public class MyTypeFilter implements TypeFilter{
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前正在扫描的类注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前正在扫描的类的资源路径
Resource resource = metadataReader.getResource();
//获取当前正在扫描的类的类名
String className = classMetadata.getClassName();
//返回true时该类匹配
if(className.contains("Controller")) {
return true;
}
return false;
}
}


等同于spring-context.xml中配置:

<context:component-scan base-package="com.yt.*" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:include-filter type="assignable" expression="com.yt.model.User"/>
<context:exclude-filter type="assignable" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="custom" expression="com.yt.conf.MyTypeFilter"/>
</context:component-scan>


@Bean

用于导入第三方的bean

public class MainConfig {
/**
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#SCOPE_PROTOTYPE
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#SCOPE_SINGLETON
* @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
*/
@Lazy //懒加载,仅对singleton作用,因为prototype原本就是懒加载
@Bean(name = "person") //默认是方法名作为id
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)//prototypeIOC容器启动时不会加载,singleton在IOC容器启动时会被加载
public Person person(){
System.out.println("init");
return new Person("lisi" ,20);
}
}


@Import

/**
* @{@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
* or regular component classes to import.
*/
@Import({MyImportBeanDefinitionRegistrar.class,Person.class, MyImportSelector.class})
public class MainConfig {
}


自定义ImportSelector

public class MyImportSelector implements ImportSelector {
//返回值不允许null,否则会抛出NullPointException
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.yt.model.Person","com.yt.model.Human"};
}
}


自定义ImportBeanDefinitionRegistrar

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
//importingClassMetadata包含了所有bean的注解元数据,register包含了bean定义信息和注册bean方法
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean definition = registry.containsBeanDefinition("user");
if(!definition) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(User.class);
registry.registerBeanDefinition("user",rootBeanDefinition);
}
}
}


bean工厂

实现Spring提供的FactoryBean,默认获取的是工厂Bean调用的getObject创建的对象,获取工厂Bean本身,需要在id前面加上&

自定义bean工厂

public class UserFactoryBean implements FactoryBean{
/**
* 获取对象
* @throws Exception
*/
public Object getObject() throws Exception {
return new User();
}
/**
* 返回对象的类型
*/
public Class<?> getObjectType() {
return User.class;
}
/**
* 是否创建一个单例对象
*/
public boolean isSingleton() {
return false;
}
}


@Configuration
public class MainConfig {
/**
* 返回的是getObject方法id为userFoctoryBean的实例
*/
@Bean
public UserFactoryBean userFactoryBean() {
return new UserFactoryBean();
}
}


UserFactoryBean实例的id是“&userFactoryBean”

@Conditional

@Bean(name = "linux")
@Conditional(value = {LinuxCondition.class})
public Person linuxPerson() {
System.out.println("Linus Torvalds");
return new Person("Linus Torvalds",48);
}
@Bean(name = "windows")
@Conditional(value = {WindowsCondition.class})
public Person windowsPerson() {
System.out.println("Bill Gates");
return new Person("Bill Gates",65);
}


实现Condition接口可条件注册组件

public class WindowsCondition implements Condition{
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//获取到IOC容器中使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取类加载器
ClassLoader classLoader = context.getClassLoader();
//获取当前环境变量
Environment environment = context.getEnvironment();
//获取的bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
//获取源文件加载器
ResourceLoader resourceLoader = context.getResourceLoader();
//获取当前操作系统
String property = environment.getProperty("os.name");
if(property.contains("Windows")) {
return true;
}
return false;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: