Spring配置文件中的<property></property>元素所指定的属性名和Bean实现类的Setter方法知足Sun JavaBean的属性命名规范:xxx的属性对应的setXxx()方法。 注意:须要知足:"变量的前两个字母要全大写,要么全小写"。不然会出现具备误导性的错误。java
1.须要提供一个有参构造函数,能够按类型匹配注入,按因此匹配注入,联合类型和因此匹配注入,经过自身类型反射匹配注入 2.构造函数注入的问题,可能出现循环依赖的问题,致使程序没法启动,只要改为属性注入便可解决这个问题。 例子: ConstructorInject.javaweb
public class ConstructorInject { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); Person person = (Person) ctx.getBean("p2"); System.out.println(person.toString()); } }
iocdemo.xmlspring
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="person" class="com.flexible.beans.Person"> <property name="userName"><value>zhangsan</value></property> <property name="userAge"><value>20</value></property> </bean> <bean id="p2" class="com.flexible.beans.Person"> <constructor-arg type="java.lang.String"><value>zhangsan</value></constructor-arg> <constructor-arg type="java.lang.Integer"><value>28</value></constructor-arg> </bean> </beans>
Person.javaexpress
public class Person { public String userName; public Integer userAge; public Person() { } public Person(String userName, Integer userAge) { this.userName = userName; this.userAge = userAge; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getUserAge() { return userAge; } public void setUserAge(Integer userAge) { this.userAge = userAge; } [@Override](https://my.oschina.net/u/1162528) public String toString() { return "Person{" + "userName='" + userName + '\'' + ", userAge=" + userAge + '}'; } }
1.非静态的工厂 xml配置以下: <bean id="factory" class="com.flexible.factorymethod.NonStaticFactoryMethod"></bean> <bean id="p3" factory-bean="factory" factory-method="createPerson"></bean> 2.工厂代码以下: /** * 使用非静态的工厂 */ public class NonStaticFactoryMethod { /** * 工厂的建立方法 * [@return](https://my.oschina.net/u/556800) */ public Person createPerson(){ Person p = new Person(); p.setUserName("lisi"); p.setUserAge(20); return p; } }
测试方法以下:缓存
//非静态的方式 ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); Person person = (Person) ctx.getBean("p3"); System.out.println(person.toString());
静态方法: xml配置以下: <bean id="p4" class="com.flexible.factorymethod.StaticMethod" factory-method="createPerson"></bean> 工厂类以下: public class StaticMethod {session
/** * 工厂的建立方法 * * [@return](https://my.oschina.net/u/556800) */ public static Person createPerson() { Person p = new Person(); p.setUserName("lisi"); p.setUserAge(20); return p; } }
测试方法: //静态的方式 Person person2 = (Person) ctx.getBean("p3"); System.out.println(person2.toString());ide
Spring不但能够将String,int等字面值注入Bean中,还能够将集合,Map等类型的数据注入Bean中,还能够注入配置文件的其余Bean。函数
字面值标识可使用字符串表示的值,这些值能够经过<value></value>元素注入。xml中包含5个特殊字符,分别是&,<,>,`,'。若是包含这些这些特殊字符,就须要使用<![CDATA[]]特殊标签。测试
注意: 通常状况下,XML解析器会忽略元素标签内部字符串的先后空格,可是Spring却不会忽略元素标签内部字符串的字符串的先后空格,若是经过如下配置为属性注入值<property name="xx"><value> xxx xx</value></property>,那么先后,中间的空格将会被一块儿赋值给xx属性。flex
xml文件以下:
<bean id="p5" class="com.flexible.beans.Person"> <property name="userName" value="wangwu"></property> <property name="userAge" value="20"></property> </bean> <bean id="h1" class="com.flexible.beans.House"> <property name="length" value="100"></property> <property name="width" value="80"></property> <property name="height" value="60"></property> <property name="person"><ref bean="p5"></ref></property> </bean>
<ref></ref>元素能够经过如下3个属性引用容器中的其余Bean。 1.bean:经过该属性能够引用同一容器或者父容器中的Bean,这是最多见的形式 2.local:经过该属性只能引用同一配置文件中定义的Bean,他能够利用XML解析器自动检验引用的合法性,以便开发者再编写配置时可以几时发现并纠正配置的错误。 3.parent:引用父容器中的Bean,如<ref parent="car">的配置说明car的Bean是父容器中的Bean.
Bean类 public class House {
private Double length; private Double width; private Double height; private Person person; public House() { } public Double getLength() { return length; } public void setLength(Double length) { this.length = length; } public Double getWidth() { return width; } public void setWidth(Double width) { this.width = width; } public Double getHeight() { return height; } public void setHeight(Double height) { this.height = height; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } [@Override](https://my.oschina.net/u/1162528) public String toString() { return "House{" + "length=" + length + ", width=" + width + ", height=" + height + ", person=" + person + '}'; } }
测试例子:
public class BeanInjectDemo { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); House house = (House) ctx.getBean("h1"); System.out.println(house.toString()); } }
内部Bean和Java的匿名内部类类似,既没有名字,也不能被其余的Bean引用,只能在声明处为外部Bean提供实例注入。 内部Bean几时提供了id,name,scope属性,也会被忽略。scope默认prototype类型。
<bean id="h1" class="com.flexible.beans.House"> <property name="length" value="100"></property> <property name="width" value="80"></property> <property name="height" value="60"></property> <property name="person"> <bean id="p5" class="com.flexible.beans.Person"> <property name="userName" value="wangwu"></property> <property name="userAge" value="20"></property> </bean> </property> </bean>
若是但愿给Bean的某个属性赋值一个null,若是使用<property name="xx"><value></value></property>这样是达不到预期的效果的,可是可使用<property name="xx"><null/></property>
javaBean代码
public class Car { Person person = new Person(); public Car() { } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } [@Override](https://my.oschina.net/u/1162528) public String toString() { return "Car{" + "person=" + person + '}'; } }
xml配置以下:
<bean id="car" class="com.flexible.beans.Car"> <property name="person.userName" value="zhaoliu"></property> <property name="person.userAge" value="20"></property> </bean>
测试代码:
public class CascadeDemo { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); Car car = (Car) ctx.getBean("car"); System.out.println(car.toString()); } }
Favorite.java
public class Favorite { /** * List集合 */ private List<String> favoties = new ArrayList<>(); /** * map集合 */ private Map<String,String> map = new HashMap<>(); /** *property,看做是特殊的map */ private Properties properties = new Properties(); public Favorite() { } public List<String> getFavoties() { return favoties; } public void setFavoties(List<String> favoties) { this.favoties = favoties; } public Map<String, String> getMap() { return map; } public void setMap(Map<String, String> map) { this.map = map; } public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } @Override public String toString() { return "Favorite{" + "favoties=" + favoties + ", map=" + map + ", properties=" + properties + '}'; } }
xml配置以下:
<bean id="favorities" class="com.flexible.beans.Favorite"> <property name="favoties"> <list> <value>游泳</value> <value>足球</value> <value>篮球</value> <value>棒球</value> </list> </property> <property name="map"> <map> <entry> <key><value>k1</value></key> <value>运动</value> </entry> <entry> <key><value>k2</value></key> <value>上班</value> </entry> <entry> <key><value>k3</value></key> <value>约会</value> </entry> </map> </property> <property name="properties"> <props> <prop key="k1">value1</prop> <prop key="k2">value2</prop> <prop key="k3">value3</prop> </props> </property> </bean> <!--集合的合并--> <bean id="childFavorities" parent="favorities"> <property name="favoties"> <list merge="true"> <value>赛车</value> </list> </property> <property name="map"> <map merge="true"> <entry> <key><value>k12</value></key> <value>运动2</value> </entry> <entry> <key><value>k22</value></key> <value>上班2</value> </entry> <entry> <key><value>k32</value></key> <value>约会2</value> </entry> </map> </property> <property name="properties"> <props merge="true"> <prop key="k12">value12</prop> <prop key="k22">value22</prop> <prop key="k32">value32</prop> </props> </property> </bean>
测试代码:
public class CollectionAttributeInject { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); Favorite favorite = (Favorite) ctx.getBean("favorities"); System.out.println(favorite.toString()); Favorite childFavorities = (Favorite) ctx.getBean("childFavorities"); System.out.println(childFavorities.toString()); } }
Spring支持使用一个Bean的方法取替换另外一个Bean的方法,替换别的Bean的Bean须要实现org.springframework.beans.factory.support.MethodReplacer接口,Spring利用该接口去替换目标Bean的方法.
被替换的类的方法:
public class Boss { public House getHouse(){ House house = new House(); house.setHeight(1.0); house.setLength(2.0); house.setLength(3.0); house.setWidth(4.0); return house; } }
替换的类须要实现org.springframework.beans.factory.support.MethodReplacer接口。
public class Boss2 implements MethodReplacer{ @Override public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { House house = new House(); house.setHeight(1.01); house.setLength(2.01); house.setLength(3.01); house.setWidth(4.01); return house; } }
xml配置文件以下:
<bean id="boss1" class="com.flexible.inject.methodreplace.Boss"> <replaced-method name="getHouse" replacer="boss2"></replaced-method> </bean> <bean id="boss2" class="com.flexible.inject.methodreplace.Boss2"></bean>
父<bean></bean>主要功能是简化子<bean></bean>的配置,因此通常声明未abstract="true",表示这个bean不实例化为一个对应的Bean。
例子:
xml配置以下:
<!--这里将这个bean声明为abstract,代表它不会被实例化为bean--> <bean id="parent" class="com.flexible.beans.Parent" abstract="true"> <property name="height" value="1.70"></property> <property name="weight" value="130"></property> </bean> <bean id="child" parent="parent"> <property name="height" value="1.80"></property> </bean>
Parent.java
public class Parent { private String height; private String weight; public Parent() { } public String getHeight() { return height; } public void setHeight(String height) { this.height = height; } public String getWeight() { return weight; } public void setWeight(String weight) { this.weight = weight; } @Override public String toString() { return "Parent{" + "height='" + height + '\'' + ", weight='" + weight + '\'' + '}'; } }
测试代码:
public class RelationBean { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); Parent parent = (Parent) ctx.getBean("child"); System.out.println(parent.toString()); } }
在配置中若是当前的Bean的初始化须要前置条件(即这些前置条件都得初始化彻底了才能实例化这个Bean)知足的时候,这个时候就须要使用到依赖 depends-on=""
若是须要引用到另外一个bean的id,须要使用<idref bean="xx"></idref>的方式使用,若是在同一个配置文件可使用<idref local="xx"></idref> 这样在开发的时期就能够辨别出错误。
导入其余配置文件能够是import,例如:
<import resource="classpath:iocdemo2.xml"></import>
低版本的Spring值支持两种做用域,因此才有singleton="true|false"的配置方式。Spring为了向后兼容,依然支持这种配置方式。推荐使用的配置方式:scope="<做用域类型>"
除了以上5种Bean做用域以外,Spring支持自定义Bean的做用域。经过org.springframework.beans.factory.config.Scope接口定义做用域,再经过org.springframework.beans.factory.config.CustomScopeConfigurer这个BeanFactoryPostprocessor注册自定义的Bean做用域。
Spring将Bean默认的做用域都是singleton,而且将实例化的Bean缓存再ApplicationContext的容器中,若是不但愿实例化以开始就进行,可使用lazy-init="true"实现懒加载,可是某些特殊的状况依然会提早加载。
scope="prototype"非单例做用域。它会将bean交给调用者,由调用者来管理bean的生命周期。
<!--从类路径下加载Spring配置文件,classpath关键字特指类路径下加载--> <!--这里能够多个配置文件,建议采用逗号隔开的方式--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:flexible-context.xml</param-value> </context-param> <!--负责启动Spring容器的监听器,他将引用上面的上下文件参数获取Spring配置文件的地址--> <!--该监听器在web容器启动时自动运行,它会根据contextConfigLocation Web容器参数获取Spring配置文件,而且启动Spring容器。--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
正常的状况咱们只须要咱们只须要经过ContextLoadListoner(或者ContextLoadServlet)将Web容器与Spring容器进行整合,可是若是须要使用request,session,globalSession这三个WEB相关的做用域,就须要也配置requestContextListiner(实现了ServletRequestListener监听器接口),ContextLoadListener只是负责监听容器的启动和关闭。若是Spring须要request,session,globalSession的支持就须要获取Web容器的HTTP请求事件,此时RequestContestListener就能够实现这个需求。
配置以下:
<!--须要三大web容器做用域时须要这个配置--> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
request:请求结束后,实例就会销毁。 session:横跨整个HTTPSession ,Session的全部HTTP请求共享同一个实例,HTTPSession结束后,实例销毁。 globalSession做用域:globalSession做用域累死与session做用域,只能再Portlet的Web应用种使用。Portlet规范定义了全局Session的概念,它被组成的Portlet Web应用全部子Portlet共享,若是不在Portlet Web应用的环境下,那么globalSession==session做用域。
须要启用<aop:scoped-proxy></aop:scoped-proxy>
通常状况下,Spring经过反射机制利用<bean></bean>的class属性指定实现类实例化Bean。在某些状况下,实例化Bean的过程比较复杂,若是按照传统的方式,须要提供大量的配置信息。配置方式收到了限制。Spring为此提供了一个org.springframework.beans.factory.FactoryBean工厂类结论,用户可能够经过实现改工厂类接口定制实例化Bean的逻辑。 例子: HouseFactoryBean.java
public class HouseFactoryBean implements FactoryBean<House> { Person person; public Person getPerson() { return person; } //接受参数 public void setPerson(Person person) { this.person = person; } //实例化bean @Override public House getObject() throws Exception { House house = new House(); house.setLength(1.0); house.setWidth(2.0); house.setHeight(3.0); house.setPerson(person); return house; } //返回Hourse类型 @Override public Class<House> getObjectType() { return House.class; } //比闹事通FactoryBean返回的Bean是singleton @Override public boolean isSingleton() { return false; } @Override public String toString() { return "HouseFactoryBean{" + "person=" + person + '}'; } }
xml配置文件
<bean id="hoursebean" class="com.flexible.beans.HouseFactoryBean"> <property name="person"> <bean id="personp" class="com.flexible.beans.Person"> <property name="userAge" value="20"></property> <property name="userName" value="zhouqi"></property> </bean> </property> </bean>
测试代码:
public static void main(String[] args) throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); House house = (House) ctx.getBean("hoursebean"); System.out.println(house.toString()); //若是想拿到HouseFactoryBean实例,就须要 &hoursebean HouseFactoryBean houseFactoryBean = (HouseFactoryBean) ctx.getBean("&hoursebean"); System.out.println(houseFactoryBean.toString()); House object = houseFactoryBean.getObject(); System.out.println(object.toString()); }
执行结果:
House{length=1.0, width=2.0, height=3.0, person=Person{userName='zhouqi', userAge=20}} HouseFactoryBean{person=Person{userName='zhouqi', userAge=20}} House{length=1.0, width=2.0, height=3.0, person=Person{userName='zhouqi', userAge=20}}
Spring提供了四个定义Bean的注解,分别是:
1.@Repository:用于对DAO实现类进行标注
2.@Service:用于对Service实现类进行标注。
3.@Controller:用于对Controller实现类进行标注
4.@Component能够代替上面任何一个,只不过上面这些标注有特殊的用途,能一目了然的看出来这个bean的用途。
Spring提供了一个Context命名空间,它提供了经过扫面类包以应用注解定义Bean的方式。 例如:<context:component-scan base-package="com.flexible"></context:component-scan>
若是但愿扫描的是特定的类而非基础包下的类,可使用resource-pattern熟悉过滤
<context:component-scan base-package="com.flexible" resource-pattern="xx/*.class"></context:component-scan>
若是还须要更加具体的过滤,如实现了xx接口的,
例如:
<context:component-scan base-package="com.flexible"> <context:include-filter type="aspectj" expression="com.flexible..*Controller+"></context:include-filter> </context:component-scan>
使用 @Autoired
@Qualifier知道注入的Bean的名称。
对标准注解的@Resource(须要提供一个Bean的名字)和@Inject的支持。
@Scope("prototype")
在使用<bean></bean>进行配置时,能够经过init-method和destroy-method属性指定Bean的初始化以及容器销毁前执行的方法。Spring从2.5开始支持JSR-250中定义的@PostConstruct和@PreDestroy注解,在Spring中他们至关于init-method和destroy-method属性的功能,不过在使用注解时,能够在一个Bean中定义多个@PostConstruct和@PreDestroy方法。
例子:
LifeCyleBea.java
@Component public class LifeCyleBean { private String info; @PostConstruct public void initMethod(){ System.out.println(".....this is initMethod...."); } @PreDestroy public void destroyMethod(){ System.out.println(".....this is destroyMethod...."); } public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } }
xml配置文件开启包扫描:
<context:component-scan base-package="com.flexible"> </context:component-scan>
测试代码:
public class LifeCycleDemo { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:iocdemo.xml"); ((ClassPathXmlApplicationContext)context).destroy(); } }
执行结果: .....this is initMethod....
.....this is destroyMethod....
JavaConfig是Spring的一个子项目,旨在经过Java类的方式提供Bean的定义信息,在Spring2.0开始发布。普通的POJO只有标注@Configuration注解,就能够为Spring容器提供Bean定义的信息。每一个标注了@Bean得类方法都至关于提供了一个Bean的定义信息。经过代码进行配置要灵活点,可是配置文件配置要简洁些。
AppConfig.java
//将一个POJO标注为定义Bean的配置类 @Configuration public class AppConfig { //能够给bean一个名字,还能够配置做用域 //@Bean(name = "car") @Bean public Car getCar(){ Car car = new Car(); car.setPerson(getPerson()); return car; } @Bean public Person getPerson(){ Person person = new Person(); person.setUserName("王八"); person.setUserAge(28); return person; } }
测试代码:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); Car car = (Car) context.getBean(Car.class); System.out.println(car.toString());
1.直接经过@Configuration类启动Spring容器
Spring提供了一个AnnotationConfigApplicationContext类,它可以直接经过标注¥Configuration的Java启动Spring容器。 例如:
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotationConfigApplicationContext还支持经过编码的方式加载多个@Configuration配置类,而后刷新容器应用的配置类。 例如:
ApplicationContext context = new AnnotationConfigApplicationContext(); context.register(AppConfig.class); context.register(AppConfig2.class); context.refresh()
标注了@Configuration的配置类与标注了@Component的类同样也是一个Bean,它能够被Spring的context:compent-scan</context:compent-scan>扫描到相应的配置类便可。 例如:
<context:component-scan base-package="com.flexible" resource-pattern="AppConfig.class">
在@Configuration配置类中能够经过@ImportResource引入XML配置文件,在RefXmlConfig配置类中便可直接经过@Autowired引用XML配置文件定义的Bean. RefXmlConfig.java
@Configuration @ImportResource("classpath:iocdemo2.xml") public class RefXmlConfig { @Bean @Autowired public PenBox getPenBox(PenBox penBox){ return penBox; } }
PenBox.java
public class PenBox { private String markName; private String description; public PenBox() { } public String getMarkName() { return markName; } public void setMarkName(String markName) { this.markName = markName; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Override public String toString() { return "PenBox{" + "markName='" + markName + '\'' + ", description='" + description + '\'' + '}'; } }
测试代码:
public class RefXmlDemo { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(RefXmlConfig.class); PenBox penBox = (PenBox) context.getBean("penBox"); System.out.println(penBox.toString()); } }
执行结果:
PenBox{markName='xxx', description='description'}