开篇
最近很流行一个框架就是Spring的框架,这个框架很流行,很多人学,那么为什么学这个框架呢?
Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。
◆目的:解决企业应用开发的复杂性
◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
◆范围:任何Java应用
Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。
其实上面这些说的都是给你一个大概的介绍,让你心里有个底,就是这玩意很牛,然后接下来说提到的IOC和AOP。
IOC是什么?
IOC(Inversion of Control):控制反转,通常跟着这句话的就是一个词就是“依赖注入”。
什么是控制反转呢?为什么要控制反转呢?
举一个简单的例子吧,就是本来我去超市买酱油,然后我就得知道酱油是什么样子等一些具体的信息,然后自己去找到酱油的所在地,然后拿到酱油然后去前台交钱(这个是控制反转之前的);现在呢,我只需要找到服务员(IOC容器)告诉他,我要酱油,然后他就拿到酱油交到我们手上(这个就是控制反转之后的流程)。
是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。
是不是符合了咱们程序设计的原则了?“高内聚,低耦合”
通过上述的例子,应该很清楚的了解到这个控制反转的作用的好处了吧。
AOP是什么?
AOP(Aspect Oriented Programming):面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。
这个是什么呢?
还是用一个例子来讲吧,回忆一下进出地铁站的流程,你的目的是坐地铁,但是坐地铁之前,你得先检票进入地铁站,坐完地铁之后,再检票出站。这个流程相信大家都看的很清楚了,本来自己的目的是坐地铁,但是坐之前和坐之后都进行了检票操作,这个就相当于面向切面编程了。(这个下一篇再具体说)。
1.导包
核心容器(IOC)需要:(四个组件)
spring-beans-5.0.0.RELEASE.jar
spring-context-5.0.0.RELEASE.jar
spring-core-5.0.0.RELEASE.jar
spring-expression-5.0.0.RELEASE.jar
Spring5.0以前运行时依赖一个日志包:没有就报错;
Spring5.0使用默认的日志包jcl,直接改写了源码
spring-jcl-5.0.0.RELEASE.jar
2.写配置
创建Spring Bean Configuration文件,在IDEA中直接就是Spring Config
在创建好的配置文件中,注册自己的类,即将写好的类放入容器中
在<beans>标签中注册,里面的一个<bean>标签注册一个对象
写好之后可以创建单元测试模块测试一下
注意事项:
1)、src或者说源码包开始的路径,称为类路径的开始
所有的源码包的东西都会被合并到类路径里:
java:/bin/
javaweb:/WEB-INF/classes/
2)、容器对象(单实例或者“被依赖”)在容器被创建的时候就创建完成了
并且是先创建对象,然后才启动容器
3)、同一组件在IOC容器中是单实例,即只有一份
4)、容器中如果没有这个容器,如果获取,就会报错,出异常
5)、IOC容器在创建这个组件的时候,(property标签)是调用setter方法为javaBean的属性赋值
6)、javaBean的属性名是由setter和getter方法所决定的而不是自己创建的时候命名的
猜测原理:利用反射机制,获取setter/getter方法的名字,然后去掉set/get,再然后剩余的首字母变小写
7)、配置文件中使用<bean>下面的<property>标签时,你自己的类中至少必须有一个无参的构造方法,或者
没有一个构造方法
3.总结
1.ioc是一个容器,帮我们管理所有的组件
依赖注入:@Autowired自动赋值
某个组件要使用Spring提供的更多(IOC、AOP)必须要加入到容器中
2.收获和思考
容器启动,创建使用的单实例bean
autowired自动装配的时候,是从容器中找这些符合要求的bean
ioc.getBean("")的时候也是从容器中找
容器包含了所有的bean
spring容器到底是什么? ->其实就是一个map
这个map中保存所有创建好的bean,并提供外界获取的功能。。。
源码调试思路:
从helloworld开始,给helloworld每一个关键的步骤打上断点,进去看里边都做了什么?
怎么知道哪些方法是做什么的?
1.先翻译这个方法是干什么的
2.放行这个方法,看控制台或者看debug的每一个变量的变化
3.看方法名,看方法的注释
1)规范注释 2)规范方法名和类名
IOC源码:
1.IOC是一个容器
2.容器启动的时候创建所有的单实例bean
3.我们可以直接从容器中获得到这个对象
SpringIOC:
1)、IOC容器的启动过程?启动期间都做了什么(什么时候创建所有的单实例bean)
2)、IOC是如何创建这些单实例bean,并如何管理的,到底保存在了哪里?
ApplicationContext的构造器:
applicationContext = new ClassPathXmlApplicationContext(“ioc.xml”);
this(new String[]{configLocation}, true, (ApplicationContext)null);
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
//所有单实例bean创建完成
refresh();
}
}
BeanFactory:Bean工厂(接口下的)
refresh();实现
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备此上下文以进行刷新。
prepareRefresh();
// 告诉子类刷新内部bean工厂。
//Spring解析xml配置文件将要创建的所有的bean的配置信息保存起来
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备在这种情况下使用的bean工厂。
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中对bean工厂进行后处理。
postProcessBeanFactory(beanFactory);
// 调用在上下文中注册为bean的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截Bean创建的Bean处理器。
registerBeanPostProcessors(beanFactory);
// 为此上下文初始化消息源。
//支持国际化功能的
initMessageSource();
//为此上下文初始化事件多播器。
initApplicationEventMulticaster();
// 在特定上下文子类中初始化其他特殊bean。
//留给子类的方法
onRefresh();
// 检查侦听器bean并注册它们。
registerListeners();
// 实例化所有剩余的(非延迟初始化)单例。
//初始化所有单实例bean的地方
finishBeanFactoryInitialization(beanFactory);
// 最后一步:发布相应的事件。
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的单例以避免资源悬空。
destroyBeans();
// 重置“活动”标志。
cancelRefresh(ex);
// 将异常传播给呼叫者。
throw ex;
}
finally {
// 在Spring的核心中重置常见的自省缓存,因为我们
// 可能不再需要单例bean的元数据...
resetCommonCaches();
}
}
}
finishBeanFactoryInitialization(beanFactory);实现
AbstractApplicationContext(接口下):
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
//初始化所有单实例bean
beanFactory.preInstantiateSingletons();
}
beanFactory.preInstantiateSingletons();
DefaultListableBeanFactory: Bean工厂,创建Bean
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
// 拿到所有要创建的bean的名字
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
//按顺序创建bean
for (String beanName : beanNames) {
//根据bean的id获取到bean的定义信息
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//判断bean是单实例的,不是抽象的,不是懒加载的
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//是否是实现了FactoryBean接口的bean
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
((SmartFactoryBean<?>) factory).isEagerInit(),
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
//如果不是
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
getBean(beanName);创建bean的细节
getBean(){
//所有的getbean调的是它
doGetBean();
}
AbstractBeanFactory(接口下):doGetBean(name, null, null, false);
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//先从已经注册的单例bean的缓存中看看有没有这个bean,第一次创建是没有的
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
//拿到创建当前bean之前需要提前创建的bean。 depends-on属性,如果有,就循环创建
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
getBean(dep);
}
}
// Create bean instance.
// 判断,如果bean是单实例的,就创建bean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
@Override
public boolean containsBean(String name) {
String beanName = transformedBeanName(name);
if (containsSingleton(beanName) || containsBeanDefinition(beanName)) {
return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name));
}
// Not found -> check parent.
BeanFactory parentBeanFactory = getParentBeanFactory();
return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name)));
}
DefaultSingletonBeanRegistry(接口):默认的bean注册表
/** Cache of singleton objects: bean name --> bean instance */
//单例对象的高速缓存:(通过)bean名称-> bean实例
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
getSingleton()方法:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
//
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//创建bean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
//添加bean
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
创建好的对象最终保存到一个Map中:
IOC的众多容器容器之一:保存单实例bean的容器DefaultSingletonBeanRegistry.singletonObjects
BeanFactory和ApplicationContext的区别:
ApplicationContext是BeanFactory的子接口,
BeanFactory:bean工厂接口,负责创建bean实例,容器里面保存的所有单例bean其实是一个map
Spring最底层的一个接口
ApplicationContext:容器接口,更多的负责容器接口的实现(可以基于BeanFactory创建好的对象之上实现强大的容器功能)
容器可以从map获取这个bean,并且aop。di。这些功能是在ApplicationContext的接口下的这些类里边
BeanFactory是最底层的接口,ApplicationContext是留给程序员使用的IOC容器接口,ApplicationContext是BeanFactory的子接口,
Spring中最大的模式就是工厂模式:
5、配置(.xml)编写
<!-- 注册类对象,相当于将对象放到容器中-->
<!--一个bean标签注册一个对象;
class:写要注册的类名;
id:这个要注册类的唯一标识
-->
<bean id="person01" class="com.phj.bean.Person" >
<!-- 使用property标签为类赋值,一个property赋一个属性
name:指定属性名;
value:指定属性值
-->
<property name="name" value="张三"/>
<property name="age" value="18"/>
<property name="email" value="zhangsan@qq.com"/>
<property name="sex" value="男"/>
</bean>
<bean id="person02" class="com.phj.bean.Person">
<property name="name" value="李四"/>
<property name="sex" value="男"/>
<property name="email" value="lisi@qq.com"/>
<property name="age" value="18"/>
</bean>
<bean id="person03" class="com.phj.bean.Person">
<!--调用有参构造器进行创建对象,并进行赋值-->
<!--和构造器匹配,如果参数数目不对会报错-->
<!--constructor-arg标签:一个代表一个有参构造器的参数;-->
<!--如果标签内写了name属性,则参数顺序无所谓;如果没写name属性,则必须按照参数顺序写-->
<!--index属性为参数指定索引顺序,从0开始-->
<!--如果有多个相同参数数目的构造器,即重载的话,如果指定name就会随机赋值,可以用type来指定参数类型-->
<constructor-arg name="name" value="王五"/>
<constructor-arg name="email" value="wangwu@qq.com" />
<constructor-arg name="sex" value="男"/>
<constructor-arg name="age" value="18"/>
</bean>
<!--通过p名称空间为bean赋值,需导入p名称空间-->
<!--名称空间:在xml文件中,名称空间用来防止标签重复-->
<!--标签前面加前缀,如c:forEach-->
<bean id="person04" class="com.phj.bean.Person"
p:age="18" p:email="zhaoliu@qq.com" p:name="赵六" p:sex="男">
</bean>
<!--正确的为各种复杂的属性赋值-->
<!--1)null测试 2)引用类型测试 3)集合类型测试 4)util名称空间创建集合类型的bean测试
5)级联属性赋值测试-->
<!--所有复杂的赋值全部在标签体里边进行-->
<bean class="com.phj.bean.Person" id="person05">
<!--ref:代表引用外边的一个值,强引用,引用外边的-->
<property name="car" ref="car01"/>
</bean>
<bean class="com.phj.bean.Person" id="person06">
<property name="car">
<!--嵌套标签赋值,引用内部的标签赋值,内部标签即使写id也无法识别,只能内部使用-->
<bean class="com.phj.bean.Car">
<property name="price" value="1000000"/>
<property name="color" value="蓝"/>
<property name="name" value="奔驰"/>
</bean>
</property>
</bean>
<bean class="com.phj.bean.Car" id="car01">
<property name="name" value="宝马"/>
<property name="color" value="红"/>
<property name="price" value="1000000"/>
</bean>
<bean class="com.phj.bean.Person" id="person07">
<!--list属性赋值-->
<property name="books">
<!--list标签相当于new ArrayList<book>();-->
<list>
<!--list标签中添加每一个元素-->
<bean class="com.phj.bean.Book" p:name="西游记"/>
<!--ref 引用外部-->
<ref bean="book01"/>
</list>
</property>
<!--map类型赋值-->
<property name="maps">
<!--map标签相当于 new LinkedHashMap<>();-->
<map>
<!--一个entry代表一个键值对-->
<entry key="key01" value="手机"/>
<entry key="key02" value-ref="book01"/>
<entry key="key03">
<bean class="com.phj.bean.Car">
<property name="name" value="劳斯莱斯"/>
</bean>
</entry>
</map>
</property>
<property name="properties">
<!--props标签相当于new Properties();所有的k==v都是string,直接写到标签体里-->
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
<bean class="com.phj.bean.Book" id="book01">
<property name="name" value="三国演义"/>
</bean>
<!--util名称空间创建集合类型的bean,方便引用-->
<bean class="com.phj.bean.Person" id="person08">
<property name="maps" ref="map01"/>
</bean>
<!--相当于new LinkedHasMap<>(); -->
<util:map id="map01">
<!--直接添加元素-->
<entry key="key01" value="手机"/>
<entry key="key02" value-ref="book01"/>
<entry key="key03">
<bean class="com.phj.bean.Car">
<property name="name" value="劳斯莱斯"/>
</bean>
</entry>
</util:map>
<!--级联属性赋值,所谓的级联属性就是属性的属性-->
<bean class="com.phj.bean.Person" id="person09">
<property name="car" ref="car01"/>
<!-- -->
<property name="car.price" value="1"/>
</bean>
<!--
通过继承实现bean配置信息的重用
通过abstract属性创建一个模板bean
-->
<!--bean标签的parent属性,指定当前的bean的配置信息继承于哪个,不是父子类-->
<bean id="person10" parent="person01">
<property name="name" value="刘能"/>
</bean>
<!--bean标签的abstract属性,abstract="true"表示,这个bean是抽象的,不能获取实例,只能被继承-->
<bean id="person11" class="com.phj.bean.Person" abstract="true" parent="person07"/>
<!--
分别创建单实例和多实例的bean
-->
<!--bean之间的依赖:只是改变创建顺序,用depends-on,里面的顺序就是创建顺序-->
<!--原来bean的创建顺序是,谁在前边谁先被创建-->
<bean id="person" class="com.phj.bean.Person" depends-on="book,car"/>
<bean id="car" class="com.phj.bean.Car"/>
<!--测试bean的作用域,分别创建单实例和多实例的bean-->
<!--bean的作用域:指定bean是否是单实例的;默认是单实例
scope里面写,有四个属性
prototype:多实例
1)、在容器启动时默认不创建
2)、在获取时创建
3)、每次获取都会创建一个新的实例
singleton:单实例,默认的
1)、在容器启动完成之前就已经创建好对象,并保存在容器中了
2)、任何获取都是获取之前就已经创建好的对象
下面两个基本上不用
request:web环境下,同一次请求创建一个bean实例
session:在web环境下,同一次会话创建一个bean实例
-->
<bean id="book" class="com.phj.bean.Book" scope="prototype"/>
<!--配置通过静态工厂方法创建bean,实例工厂创建的bean、FactoryBean-->
<!--bean的创建默认就是框架利用反射机制new出来的bean实例-->
<!--工厂模式:工厂帮我们创建对象:有一个专门帮我们创建对象的类,这个类就是工厂
静态工厂:工厂本身不用被创建,通过静态方法调用,对象 = 工厂类.工厂方法名();
实例工厂:工厂本身需要被创建;
工厂类 工厂对象 = new 工厂类();
工厂对象.工厂方法();
-->
<!--1.静态工厂,factory-method属性指定哪个方法是工厂方法
class指定静态工厂的全类名-->
<bean id="airPlane01" class="com.phj.factory.AirPlaneStaticFactory" factory-method="getAirPlane">
<constructor-arg value="刘能"/>
</bean>
<!--2.实例工厂
先创建一个实例工厂对象
然后创建一个用实例工厂创建的对象,并且在这个对象里面配置属性-->
<bean id="airPlaneInstanceFactory" class="com.phj.factory.AirPlaneInstanceFactory"/>
<!--factory-bean指定当前对象的创建用哪个工厂
factory-method属性指定哪个方法是工厂方法-->
<bean id="airPlane02" factory-bean="airPlaneInstanceFactory"
factory-method="getAirPlane">
<constructor-arg value="赵四"/>
</bean>
<!--FactoryBean(是spring规定的一个接口);只要是这个接口的实现类,Spring就认为是一个工厂
Spring会自动调用,并且和其他不一样的是ioc容器在被创建的时候不会先创建对象,
而是在调用的时候才创建对象(不论单多实例)-->
<bean class="com.phj.factory.myFactory" id="book2"/>
<!--创建带有生命周期方法的bean
生命周期:bean的创建和销毁
1)、单实例bean,容器启动时被创建,容器关闭时被销毁
2)、多实例bean,获取的时候被创建
我们可以自己创建生命周期方法,在Spring创建或者销毁的时候调用
可以自定义初始化和销毁方法(init-method=""和destroy-method=""),不能设置参数,但是可以抛出异常
单例bean的生命周期:
(容器启动)构造器 > 初始化方法 > ...... > (容器关闭)销毁方法
多例bean的生命周期:
(获取时)构造器 > 初始化方法 > ...... > (容器关闭)不会销毁方法
后置处理器:
构造器 > 后置处理器的before > 初始化方法 > 后置处理器的after > ...... > (容器关闭)不会销毁方法-->
<bean class="com.phj.bean.Book" id="book3" destroy-method="destory" init-method="init"/>
<!--测试bean的后置处理器(BeanPostProcessor)
Spring有一个被称为后置处理器的接口,可以在bean的初始化前后调用
无论是否有初始化方法,后置处理器都会被调用,并且直接覆盖创建的全部类-->
<!--<bean class="com.phj.bean.myTBeanPostProcessor" id="beanPostProcessor"></bean>-->
<!--引用外部属性文件,依赖context名称空间-->
<!--数据库连接池做成单实例是最好的,一个项目就一个连接池,连接池里管理很多连接,连接直接从连接池中拿-->
<!--基于这些,所以可以让spring帮我们创建连接池对象(也就是管理连接池)-->
<!--加载外部配置文件用<context:property-placeholder>标签
classpath固定写法,表示引用类路径下的一个资源-->
<context:property-placeholder location="classpath:dbconfig.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!--${key}表示动态取出配置文件下的属性
username是spring中的一个关键字,所以用了之后会报错-->
<property name="user" value="${user}"/>
<property name="password" value="${password}"/>
<property name="jdbcUrl" value="${jdbcUrl}"/>
<property name="driverClass" value="${driverClass}"/>
</bean>
<!--基于xml的自动装配(自定义类型自动赋值,基本类型不适用)
javaBean(基本类型)
(自定义类型的属性是一个对象,这个对象在容器中可能存在)
<property>算是手动赋值
autowire属性
autowire="byName":按照名字,就是以属性名作为id在配置文件中找到一个组件为其赋值,找不到设置成null
autowire="byType":按照类型,以属性的类型作为查找依据去容器中找组件,如果有多个就报错;如果没有就设置成null
如果有个List<>属性,就会按照类型,将容器中同样类型的组件封装成一个List为其赋值
autowire="constructor":
按照构造器
1).先按照有参构造器的参数类型进行装配,没有就直接赋值为null
2).如果按照类型找到了多个,然后就将参数的名作为id继续匹配,找不到就赋值为null
-->
<bean class="com.phj.bean.Person" id="person02" autowire="constructor"/>
<!--SpEL测试,符号#{},运算符都支持,取其他bean对象的某个属性,可以通过id引用其他bean
调用静态方法 #{T(全类名).静态方法()}
调用非静态方法 #{ID.方法名()}-->
<!--通过注解分别创建Dao、Service、Controller
通过给Bean上添加某些注解,可以快速的将bean加入到ioc容器中
某个类中添加上任何一个注解都能快速的将这个组件加入到ioc容器的管理中
Spring中有四个注解:
@Controller:控制器,推荐给控制器层的组件加这个注解
@Service:业务逻辑,推荐给业务逻辑层的组件添加这个注解
@Repository:给数据库层(持久化层,dao层)的组件添加这个注解
@Component:给不属于以上层的组件添加这个注解
注解可以随便加,Spring底层不会验证这个组件和注释是否配合,但是为了方便代码管理和查看,还是要对应
使用注解将组件快速的加入到容器中的步骤:
1)、给要添加的组件加上注解
2)、告诉Spring自动扫描添加了注解的组件,依赖context名称空间
3)、<context:component-scan>标签能自动扫描组件,
base-package属性指定扫描的基础包,把基础包及他下面所有的包的所有加了注解的类自动扫描到容器中
ID为类名首字母小写,使用注解加入容器中的和使用配置加入容器中的组件行为都是默认一样的
4)、一定要导入AOP包
5)、如果修改名字,就直接在注解后面的括号里写就行,例如:@Component("名字")
6)、下面添加上@Scope("prototype")能将默认的单实例修改成多实例
7)、注解只能在自己写的代码里边写,配置适用所有代码
8)、<context:exclude-filter>扫描的时候可以排除一些不要的组件,type指定排除规则,expression写注解的全类名
type="annotation"表明按照注解进行排除(标了指定注解的不要)
type="assignable"指定某个具体的类,按类型排除
一般只用前两种
type="aspectj"按aspectj表达式
type="custom"自定义一个TypeFilter,自己写代码决定哪些使用
type="regex"还可以写正则表达式
8)、<context:include-filter>扫描的时候要扫描的组件,type指定需要规则,expression写注解的全类名,禁用掉默认的扫描规则才能生效
type="annotation"表明按照注解进行扫描(只要标了指定注解的)
-->
<context:component-scan base-package="com.phj">
<!--<context:exclude-filter type="regex" expression=""></context:exclude-filter>-->
<!--<context:include-filter type="" expression=""></context:include-filter>-->
</context:component-scan>
<!--DI(依赖注入)-->
<!--使用@Autowired注解实现根据类型自动装配
Spring会自动的为这个属性赋值,方法:Spring去容器中找到这个属性对应的组件
@Autowired原理:
1).先按照类型去容器中找到对应的组件
1).找到一个就直接赋值
2).没找到就抛异常
3).找到多个
1).按照变量名作为ID继续匹配
1).匹配上,就赋值
2).没有匹配上,报错
原因:因为我们是按照变量名作为ID继续匹配
解决:使用@Qualifier("")注解,这个注解可以指定一个ID去匹配,而不是用变量名
1).找到了,装配
2).找不到,报错
发现@Autowired自动装配的属性默认是一定装配上的,不然就报错
可以改变模式成,如果扎到了装配,找不到就赋值为null:修改成@Autowired(required=false)
方法上如果有@Autowired的话,
1).这个方法也会在bean创建的时候自动运行
2).这个方法的每一个参数都会自动注入值
-->
<!--@Autowired、@Resource、@Inject 都可以自动装配
@Autowired最强大,spring自己原装的
@Resource是j2ee的注解java的标准,扩展性更强,如果切换成别的容器框架依然可用
-->
<!--测试泛型依赖注入,注入一个组件的时候,泛型也是参考标准
spring中可以使用带泛型的父类来确定这个子类的类型-->
<context:component-scan base-package="com.phj"/>