Spring容器成功启动的必备条件
Bean 在Spring中加载的过程
package com.baobaotao.ditype;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Car {
private int maxSpeed;
private String brand;
private double price;
}
200
红旗CA72
20000.00
package com.baobaotao.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.baobaotao.ditype.Car;
public class ApplicationBeansTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Car car = (Car) context.getBean("car");
System.err.println(car);
}
}
注意:成员变量的命名规则 驼峰命名、全小写、首字母不可大写
package com.baobaotao.ditype;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Car {
private int maxSpeed;
private String brand;
private double price;
private String iDcode;
//测试1
public Car(String brand, double price) {
this.brand = brand;
this.price = price;
}
//测试2
public Car(String brand, String corp, double price) {
this.brand = brand;
this.corp = corp;
this.price = price;
}
//测试3
public Car(String brand, String corp, int maxSpeed) {
this.brand = brand;
this.corp = corp;
this.maxSpeed = maxSpeed;
}
}
package com.baobaotao.ditype;
public class Office {
}
package com.baobaotao.ditype;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Boss {
private String name;
private Car car;
private Office office;
//测试4
public Boss(String name, Car car, Office office) {
this.name = name;
this.car = car;
this.office = office;
}
}
20000
红旗CA72
John
package com.baobaotao.ditype;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Car {
private String brand;
private Boss boss;
public Car() {}
public Car(String beand, Boss boss) {
this.brand = beand;
this.boss = boss;
}
}
package com.baobaotao.ditype;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Boss {
private String name;
private Car car;
public Boss(String name, Car car) {
this.name = name;
this.car = car;
}
}
该种方法无法启动 Spring Ioc容器,因为循环依赖;解决方法:将构造函数注入方式调整为属性注入方式
package com.baobaotao.ditype;
public class CarFactory {
//非静态工厂方法
public Car createhongQiCar() {
Car car = new Car();
car.setBrand("红旗CA72");
return car;
}
//静态工厂方法
public static Car createhongQiCarStatic() {
Car car = new Car();
car.setBrand("红旗CA72");
return car;
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Car car = (Car) context.getBean("car5");
System.err.println(car);
}
}
所谓"字面值"一般是指可用字符串表示的值,这些值可以通过< value >元素标签进行注入。
XMl特殊处理标签
特殊符号 | 转义序列 |
---|---|
< | & lt; |
> | & gt; |
& | & amp; |
" | & quot; |
’ | & apos; |
注意:一般情况下,XML解析器会忽略内部字符串的前后空格,但Spring却不忽略元素标签内部字符串的前后空格。
200
红旗&CA72
beans1.xml
beans2.xml
package com.baobaotao.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.baobaotao.ditype.Boss;
import com.baobaotao.ditype.Car;
import com.baobaotao.ditype.CarFactory;
public class ApplicationBeansTest {
public static void main(String[] args) {
//父容器
ClassPathXmlApplicationContext pFactory = new ClassPathXmlApplicationContext(new String[] {"beans1.xml"});
//指定pFactory为该容器的父容器
ApplicationContext factory = new ClassPathXmlApplicationContext(new String[] {"beans2.xml"}, pFactory);
Boss boss = (Boss) factory.getBean("boss");
System.err.println(boss);
}
}
package com.baobaotao.ditype;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Boss {
...
private Car car = new Car();
}
java.util 包中的集合类是最常用的数据结构类型,主要包括 List、Set、Map、Properties,Spring 为这些集合类型属性提供了专门的配置元素标签
package com.baobaotao.ditype;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Boss {
private List favorites = new ArrayList();
private Map jobs = new HashMap();
private Set hashSet = new HashSet();
private Properties mails = new Properties();
}
看报
赛车
高尔夫
牛
娜
[email protected]
[email protected]
看报
赛车
高尔夫
爬山
游泳
dream1
dream1
dream1
set1
set2
key1
value1
key2
value2
字面值属性
引用对象属性
使用 p 命名空间
< bean>元素提供了一个指定自动装配类型的属性:autowire="<自动装配类型>" Spring 提供了4种自动装配类型
自动装配类型 | 说明 |
---|---|
byName | 根据名称进行自动匹配。假设 Boss 有一个名为 car 的属性,如果容器中刚好有一个名为 car 的 Bean ,Spring 就会自动将其装配给 Boss 的 car 属性 |
byType | 根据类型进行自动匹配。假设 Boss 有一个 Car 类型的属性,如果容器中刚好有一个 Car 类型的 Bean ,Spring 就会自动将其装配给 Boss 的 car 属性 |
constructor | 于 byType 类似,只不过它是针对构造函数注入而言的,如果Boss有一个构造函数,构造函数包含一个 Car 类型的入参,如果容器中有一个 Car 类型的 Bean,则Spring 将自动把这个 Bean 作为 Boss 构造函数的入参,如果容器中没有找到和构造函数入参匹配类型的Bean,Spring 将抛出异常 |
autodetect | 根据 Bean 的自省机制决定采用 byType 还是 constructor 进行自动装配:如果Bean提供了默认的构造函数,则采用 byType;否则采用constructor |
package com.baobaotao.injectfun;
import com.baobaotao.ditype.Car;
public interface MagicBoss {
Car getCar();
}
package com.baobaotao.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.baobaotao.ditype.Boss;
import com.baobaotao.ditype.Car;
import com.baobaotao.ditype.CarFactory;
import com.baobaotao.injectfun.MagicBoss;
public class ApplicationBeansTest {
public static void main(String[] args) {
ApplicationContext factory = new ClassPathXmlApplicationContext("beans.xml");
MagicBoss car = (MagicBoss) factory.getBean("magicBoss");
System.err.println(car.getCar());
}
}
package com.baobaotao.injectfun;
import com.baobaotao.ditype.Car;
public class Boss1 {
public Car getCar() {
Car car = new Car();
car.setBrand("宝马Z4");
return car;
}
}
package com.baobaotao.injectfun;
import java.lang.reflect.Method;
import org.springframework.beans.factory.support.MethodReplacer;
import com.baobaotao.ditype.Car;
public class Boss2 implements MethodReplacer{
public Object reimplement(Object arg0, Method arg1, Object[] arg2) {
Car car = new Car();
car.setBrand("美洲豹");
return car;
}
}
package com.baobaotao.entity;
public class SystemSettings {
public static int SESSION_TIMEOUT = 30;
public static int REFRESH_CYCLE = 60;
}
package com.baobaotao.entity;
public class SysInit {
public SysInit() {
SystemSettings.SESSION_TIMEOUT = 10;
SystemSettings.REFRESH_CYCLE = 100;
}
}
package com.baobaotao.entity;
import java.util.Timer;
import java.util.TimerTask;
public class CacheManager {
public void cacheManager() {
System.err.println( SystemSettings.REFRESH_CYCLE);
}
}
方法一:一个 XML 配置文件可以通过 < import> 组合多个外部的配置文件,resource 属性支持 Spring 标准的资源路径
beans1.xml
方法二:通过 new String[]{“beans1.xml”,“beans1.xml”}
package com.baobaotao.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.baobaotao.ditype.Boss;
import com.baobaotao.ditype.Car;
public class ApplicationBeansTest {
public static void main(String[] args) {
ApplicationContext factory = new ClassPathXmlApplicationContext(new String[] {"beans1.xml", "beans2.xml"});
Car car1 = (Car) factory.getBean("car1");
Boss boss2 = (Boss) factory.getBean("boss2");
System.err.println(car1);
System.err.println(boss2);
}
}
类 别 | 说 明 |
---|---|
singleton | 在 Spring IoC 容器中仅存在一个 Bean 实例, Bean 以单实例的方式存在 |
prototype | 每次从容器中调用 Bean 时,都返回一个新的实例,即每次调用getBean()时,相当于执行 new XxxBean() 的操作 |
request | 每次 HTTP 请求都会创建一个新的 Bean。该作用域仅适用于 WebApplicationContext环境 |
session | 同一个 HTTP Session 共享一个 |
globalSession | 在 Spring IoC 容器中仅存在一个 Bean 实例, Bean 以单实例的方式存在 |
无状态或者状态不可变的类适合使用单实例模式;
@1
@2
@3
@4
@1
@2
@3
@4
使用 Spring 的 WebApplicationContext,则还可以使用另外 3 种 Bean 的作用域:request、session和 globalSession。当然必须再 Web 容器中进行额外的配置。
Web 容器中进行配置
org.springframework.web.context.request.RequestContextListener
request 作用域
session作用域
globalSession 作用域
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
Spring 通过反射机制利用< Bean > 的class 属性指定实现类实例化 Bean。
从Spring 3.0 开始,FactoryBean 开始支持泛型,即接口声明改为 FactoryBean< T>的形式;该接口中定义了以下3个接口方法
package com.baobaotao.fb;
import org.springframework.beans.factory.FactoryBean;
import com.baobaotao.ditype.Car;
public class CarFactoryBean implements FactoryBean{
private String carInfo;
public String getCarInfo() {
return carInfo;
}
//@1 接收逗号分割的属性设置信息
public void setCarInfo(String carInfo) {
this.carInfo = carInfo;
}
//@2 实例化 Car Bean
@Override
public Car getObject() throws Exception {
Car car = new Car();
String[] infos = carInfo.split(",");
car.setBrand(infos[0]);
car.setMaxSpeed(Integer.valueOf(infos[1]));
car.setPrice(Double.valueOf(infos[2]));
return car;
}
//@3 返回Car 的类型
@Override
public Class getObjectType() {
return Car.class;
}
public boolean isSingleton() {
return false;
}
}
package com.baobaotao.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.baobaotao.ditype.Car;
import com.baobaotao.fb.CarFactoryBean;
public class ApplicationBeansTest {
public static void main(String[] args) throws Exception {
ApplicationContext factory = new ClassPathXmlApplicationContext("beans.xml");
//该方法返回 Car Bean对象 getBean("car')
//Car cfb = (Car) factory.getBean("car");
//若希望获取CarFactoryBean 自身的实例 则需再 beanName 前加 ‘&’ getBean("&car')
CarFactoryBean cfb = (CarFactoryBean) factory.getBean("&car");
System.err.println(cfb.getCarInfo());
Car car = cfb.getObject();
System.err.println(car);
System.err.println(cfb.getObjectType());
System.err.println(cfb.isSingleton());
}
}
类 别 | 示例 | 说 明 |
---|---|---|
annotation | com.baobaotao.XxxAnnotation | 所有标注了 XxxAnnotation 的类。该类型采用目标类是否标注了某个注解进行过滤 |
assignable | com.baobaotao.XxxService | 所有继承或扩展 XxxService 的类。该类型采用目标类是否继承或扩展某个特定类进行过滤 |
aspectj | com.baobaotao…*Service+ | 所有类名以 Service 结束的类及继承或扩展他们的类。该类型采用 AspectJ 表达式经写过滤 |
regex | com.baobaotao.anno…* | 所有com.baobaotao.anno 类包下的类。该类型采用正式表达式根据目标类的类名进行过滤 |
custom | com.baobaotao.XxxTypeFilter | 采用 XxxTypeFile 通过代码的方式根据过滤规则。该类必须实现 org.springframework.core.type.TypeFilter 接口 |
package com.baobaotao.anno.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baobaotao.anno.dao.LogDao;
import com.baobaotao.anno.entity.UserBo;
//@1 定义一个Service的Bean
@Service
public class LogonService {
// @2 分别注入 LogDao 及 UserDao 的 Bean
@Autowired(required=false)
private LogDao logDao;
public void logInUser() {
UserBo user = new UserBo();
System.out.println(user);
}
}
使用 @Qualifier 指定注入 Bean 的名称
package com.baobaotao.anno.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.baobaotao.anno.dao.LogDao;
import com.baobaotao.anno.dao.UserDao;
@Service
public class LogonService {
@Autowired(required=false)
private LogDao logDao;
// 注入名为userDao,类型为 UserDao 的 Bean
@Autowired
@Qualifier("userDao")
private UserDao userDao;
}
对类方法进行标注
package com.baobaotao.anno.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.baobaotao.anno.dao.LogDao;
import com.baobaotao.anno.dao.UserDao;
@Service
public class LogonService {
private LogDao logDao;
private UserDao userDao;
//自动将LogDao 传给方法入参
@Autowired
public void setLogDao(LogDao logDao) {
this.logDao = logDao;
System.out.println("logDao:" +logDao);
}
//自动将名为 userDao 的 Bean 传给方法入参
@Autowired
@Qualifier("userDao")
public void getUserInfo(UserDao userDao) {
this.userDao = userDao;
System.out.println("userDao:" + userDao);
}
//Spring 自动选择匹配入参类型的 Bean 进行注入
@Autowired
public void getUserInfo(UserDao userDao, LogDao logDao) {
this.userDao = userDao;
System.out.println("userDao:" + userDao + " LogDao:" + logDao);
}
// 如果一个方法拥有多个入参,默认情况下,Spring 自动选择匹配入参类型的 Bean 进行注入, Sprig 允许对方法入参标注@Qualifier 以指定注入 Bean 的名称
@Autowired
public void getUserInfo(@Qualifier("userDao")UserDao userDao, LogDao logDao) {
this.userDao = userDao;
System.out.println("userDao:" + userDao + " LogDao:" + logDao);
}
}
对集合类进行标注
package com.baobaotao.anno.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyComponent {
@Autowired(required=false)
private List plugin;
public List getPlugins(){
return plugin;
}
}
package com.baobaotao.anno.service;
public interface Plugin {
}
package com.baobaotao.anno.service.impl;
import org.springframework.stereotype.Component;
import com.baobaotao.anno.service.Plugin;
@Component
public class OnePlugin implements Plugin{
}
package com.baobaotao.anno.service.impl;
import org.springframework.stereotype.Component;
import com.baobaotao.anno.service.Plugin;
@Component
public class TwoPlugin implements Plugin{
}
package com.baobaotao.ditype;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Scope("prototype")
@Component
public class Car {
...
}
package com.baobaotao.anno.entity;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Boss {
private Car car;
public Boss() {
System.out.println("construce...");
}
@Autowired
public void setCar(Car car) {
System.out.println("execute in setCar");
this.car = car;
}
@PostConstruct
private void init1() {
System.out.println("execute in init1");
}
@PostConstruct
private void init2() {
System.out.println("execute in init2");
}
@PreDestroy
private void destory1() {
System.out.println("execute in destory1");
}
@PreDestroy
private void destory2() {
System.out.println("execute in destory2");
}
}
package com.baobaotao.anno;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
((ClassPathXmlApplicationContext)ctx).destroy();
}
}
package com.baobaotao.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.baobaotao.anno.dao.LogDao;
import com.baobaotao.anno.dao.UserDao;
import com.baobaotao.anno.dao.impl.LogDaoImpl;
import com.baobaotao.anno.dao.impl.UserDaoImpl;
import com.baobaotao.anno.service.LogonService;
//@1 将一个POJO标注为定义 Bean 的配置类
@Configuration
public class AppConf {
//@2 以下两个方法定义了两个 Bean,并提供了 Bean 的示例化逻辑
@Bean
public UserDao userDao() {
return new UserDaoImpl();
}
@Bean
public LogDao logDao() {
return new LogDaoImpl();
}
//@3 定义了 logonService 的 Bean
@Bean
public LogonService logonService() {
LogonService logonService = new LogonService();
//@4 将@2和@3处定义的 Bean 注入到logonService Bean 中
logonService.setLogDao(logDao());
logonService.getUserInfo(userDao(), logDao());
return logonService;
}
}
package com.baobaotao.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.baobaotao.anno.dao.LogDao;
import com.baobaotao.anno.dao.UserDao;
import com.baobaotao.anno.dao.impl.LogDaoImpl;
import com.baobaotao.anno.dao.impl.UserDaoImpl;
@Configuration
public class DaoConfig {
@Bean
public UserDao userDao() {
return new UserDaoImpl();
}
@Bean
public LogDao logDao() {
return new LogDaoImpl();
}
}
package com.baobaotao.conf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import com.baobaotao.anno.service.LogonService;
@Configuration
public class ServiceConfig {
//@1 像普通 Bean 一样注入 DaoConfig
@Autowired
private DaoConfig daoConfig;
public LogonService logonService() {
LogonService logonService = new LogonService();
//@2 像普通 Bean 一样,调用 Bean 相关的方法
logonService.setLogDao(daoConfig.logDao());
logonService.getUserInfo(daoConfig.userDao(), daoConfig.logDao());
return logonService;
}
}
package com.baobaotao.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import com.baobaotao.anno.dao.LogDao;
import com.baobaotao.anno.dao.impl.LogDaoImpl;
@Configuration
public class DaoConfig2 {
@Scope("prototype")
@Bean
public LogDao logDao() {
return new LogDaoImpl();
}
}
package com.baobaotao.anno;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.baobaotao.anno.service.LogonService;
import com.baobaotao.conf.AppConf;
public class JavaConfigTest {
public static void main(String[] args) {
/* //测试方法一:
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConf.class);
LogonService logonService = ctx.getBean(LogonService.class);
logonService.printHello();*/
//测试方法二:
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(DaoConfig.class);
ctx.register(ServiceConfig.class);
ctx.refresh();
LogonService logonService = ctx.getBean(LogonService.class);
logonService.printHello();
}
}
package com.baobaotao.conf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.baobaotao.anno.service.LogonService;
@Configuration
@Import(DaoConfig.class)
public class ServiceConfig {
//@1 像普通 Bean 一样注入 DaoConfig
@Autowired
private DaoConfig daoConfig;
@Bean
public LogonService logonService() {
LogonService logonService = new LogonService();
//@2 像普通 Bean 一样,调用 Bean 相关的方法
logonService.setLogDao(daoConfig.logDao());
logonService.getUserInfo(daoConfig.userDao(), daoConfig.logDao());
return logonServ
}
}
package com.baobaotao.conf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import com.baobaotao.anno.dao.LogDao;
import com.baobaotao.anno.dao.UserDao;
import com.baobaotao.anno.service.LogonService;
@Configuration
@ImportResource("classpath:beans2.xml")
public class LogonAppConfig {
@Bean
@Autowired
public LogonService logonService(UserDao userDao, LogDao logDao) {
LogonService logonService = new LogonService();
logonService.setLogDao(logDao);
logonService.getUserInfo(userDao, logDao);
return logonService;
}
}
基于 XML 配置 | 基于注解配置 | 基于Java 类配置 | |
---|---|---|---|
Bean 定义 | 在 XML 文件中同通过 < bean > 元素定义 Bean 如:< bean class=“com.hm.UserDao” > | 在 Bean 实现类处通过标注 @component 或者衍型类(@Repository、@Service和@Controller)定义 Bean | 在标注了 @Configuration 的Java类中,通过在类方法上标注 @Bean 定义一个Bean。方法必须提供 Bean 的实例化逻辑 |
Bean 名称 | 通过 < bean > 的id活name属性定义,如:< bean id=“userDao” class=“com.hm.UserDao” > 默认名称为:com.hm.UserDao#0 | 通过注解的 value 属性定义,如 @Component(“userDao”)。默认名称为小写字母打头的类名(不带包名): userDao | 通过@Bean 的 name 属性定义,如 @Bean(“userDao”),默认名称为方法名 |
Bean 注入 | 通过 < property > 子元素或通过 p 命名空间的动态属性,如 p:userDao-ref="userDao"进行注入 | 通过在成员变量或方法入参处标注 @Autowired,按类型匹配自动注入。还可以配合使用 @Qualifief 按名称匹配方法注入 | 比较灵活,可以通过在方法处通过 @Autowired 使方法入参绑定 Bean,然后在方法中通过代码注入,还可以同通过调用配置类的 @Bean 方法进行注入 |
Bean 生命过程方法 | 通过 < bean > 的 init-method 和 destroy-method 属性指定 Bean 实现类的方法名。最多只能指定一个初始化反法和一个销毁方法 | 通过在目标方法上标注 @PostConstruce 和 @preDestroy 注解指定初始化或销毁方法,可以定义任意多个方法 | 通过 @Bean 的 initMethod 或 destoryMethod 指定一个初始化或销毁方法 对于初始化方法来说,可以直接在方法内部通过代码的方式灵活定义初始化逻辑 |
Bean 作用范围 | 通过 < bean > 的 scope 属性指定,如:< bean class=“com.hm.UserDao” scope=“prototype” > | 通过在类定义处标注 @Scope 指定,如 @Scope(“prototype”) | 通过在Bean方法定义处标注 @Scope 指定 |
Bean 延迟初始化 | 通过 < bean > 的 lazy-init 属性指定,默认为 default,继承于 < beans > 的default-lazy-init 设置,该值默认为 false | 通过在类定义处标注 @Lazy 指定,如 @Lazy(true) | 通过在 Bean 方法定义处标注 @lazy 指定 |