Spring和JavaWeb

Spring和JavaWeb整合使用

  1. Spring来控制事务(DAO[JDBCTemplate])
  2. 所有组件AutoWired
  3. 管理数据库

整合步骤

  1. 导包

  2. 写配置

    1. 将所有组件加入容器中,并能正确获取
      @Controller:Servlet层,目前不能标注在Servlet层
      @Service: 业务逻辑层
      @Repository Dao层
      @Component 其他组件

    2. 每个组件之间自动装配

    3. 配置出声明式事务
      事务管理器控制数据库连接池
      IOC容器创建和销毁要在合适的时机完成

      1
      2
      3
      4
      5
      6
      项目启动{
      ioc创建
      }
      项目销毁{
      IOC销毁
      }
  3. 测试

Spring 源码

Spring AOP

动态代理
多层切面在环绕通知,内部切面的返回值会影响外部的返回值

Spring IOC

  1. IOC是一个容器
  2. 容器启动的时候创建所有单实例对象
  3. 可以直接从容器中获取到这个对象

问题

1) ioc容器的启动过程?启动时间都做了什么?什么时候创建所有单实例bean
2) ioc是如何创建单实例bean,并如何管理,这些Bean保存在哪里

调试

  1. ioc = new ClassPathXmlApplicationContext(“application.xml”);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    1. this(new String[] {configLocation}, true, null);
    2.
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
    throws BeansException {

    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
    refresh();
    }
    }

refresh();运行后所有Bean创建完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}

catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}
}
}

解析xml配置文件并创建所有配置文件下创建的Bean,将这些信息保存起来 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
initMessageSource(); 支持国际化
initApplicationEventMulticaster(); 初始化事件转换器
onRefresh(); 留给子类的方法,方便自定义容器
finishBeanFactoryInitialization(beanFactory); 初始化单实例Bean
调用上一个方法后进入, AbstractApplicationContext类中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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));
}

// 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.
beanFactory.preInstantiateSingletons();
}

beanFactory.preInstantiateSingletons(); 初始化单实例
DefaultListableBeanFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@Override
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}


//拿到所有Bean创建的名字


List<String> beanNames;
synchronized (this.beanDefinitionMap) {
// 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.
beanNames = new ArrayList<String>(this.beanDefinitionNames);
}


//按顺序创建Bean
for (String beanName : beanNames) {

//根据BeanId获取Bean的定义信息
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//如果Bean是单实例并且不是懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//是否工厂bean(即是否实现FactoryBean)
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
//创建Bean的细节
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
}

getBean调用的是doGetBean(name, null, null, false);(位于AbstractBeanFactory)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//先获取Bean名
final String beanName = transformedBeanName(name);
Object bean;

// Eagerly check singleton cache for manually registered singletons.
//先从已经创建的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 (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 dependsOnBean : dependsOn) {
if (isDependent(beanName, dependsOnBean)) {
throw new BeanCreationException("Circular depends-on relationship between '" +
beanName + "' and '" + dependsOnBean + "'");
}
registerDependentBean(dependsOnBean, beanName);
getBean(dependsOnBean);
}
}

// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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 '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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 && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
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;
}

DefaultSingletonBeanRegistry类
getSingleton 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* Return the (raw) singleton object registered under the given name,
* creating and registering a new one if none registered yet.
* @param beanName the name of the bean
* @param singletonFactory the ObjectFactory to lazily create the singleton
* with, if necessary
* @return the registered singleton object
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
//先将Bean get出来
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while the 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 recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<Exception>();
}
try {
singletonObject = singletonFactory.getObject();
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
//添加创建的bean
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}

1
2
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
  • addSingleton方法(创建的Bean最终保存)
    1
    2
    3
    4
    5
    6
    7
    8
    protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
    this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
    this.singletonFactories.remove(beanName);
    this.earlySingletonObjects.remove(beanName);
    this.registeredSingletons.add(beanName);
    }
    }

BeanFacory总结

BeanFactory和ApplicationContext的区别?
ApplicationContext是BeanFactory的子接口
BeanFactory : Bean工厂,赋值Bean的创建,容器中保存的单例Bean其实是一个map
ApplicationContext:容器接口,负责容器容器功能的实现(可以基于BeanFactory创建好的对象之上完成强大的容器)
容器可以从map获取这个Bean,并且aop,DI(依赖注入)这些功能是在ApplicationContext接口下的这些类里面
BeanFactory最底层的接口,ApplicationContext留给程序员使用的ioc容器接口
Spring最大的模式就是工厂模式

Spring 声明式事务

事务概述

  • 在JavaEE企业级开发的应用领域,为了保证数据的 完整性和一致性 ,必须引入数据库事务的概念,所以事务管理是企业级应用程序开发中必不可少的技术。
  • 事务就是一组由于逻辑上紧密关联而合并成一个整体(工作单元)的多个数据库操作,这些操作 要么都执行,要么都不执行
  • 事务的四个关键属性(ACID)
    • 原子性 (atomicity):“原子”的本意是“不可再分”,事务的原子性表现为一个事务中涉及到的多个操作在逻辑上缺一不可。事务的原子性要求事务中的所有操作要么都执行,要么都不执行。
    • 一致性 (consistency):“一致”指的是数据的一致,具体是指:所有数据都处于满足业务规则的一致性状态。一致性原则要求:一个事务中不管涉及到多少个操作,都必须保证事务执行之前数据是正确的,事务执行之后数据仍然是正确的。如果一个事务在执行的过程中,其中某一个或某几个操作失败了,则必须将其他所有操作撤销,将数据恢复到事务执行之前的状态,这就是回滚。
    • 隔离性 (isolation):在应用程序实际运行过程中,事务往往是并发执行的,所以很有可能有许多事务同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。隔离性原则要求多个事务在并发执行过程中不会互相干扰。
    • 持久性(durability):持久性原则要求事务执行完成后,对数据的修改永久的保存下来,不会因各种系统错误或其他意外情况而受到影响。通常情况下,事务对数据的修改应该被写入到持久化存储器中。

拓展: 在大数据中的新型数据库中存在严格一致性


Spring JDBCTemplate

概述

为了使JDBC更加易于使用,Spring在JDBC API上定义了一个抽象层,以此建立一个JDBC存取框架。
作为Spring JDBC框架的核心,JDBC模板的设计目的是为不同类型的JDBC操作提供模板方法,通过这种方式,可以在尽可能保留灵活性的情况下,将数据库存取的工作量降到最低。
可以将Spring的JdbcTemplate看作是一个小型的轻量级持久化层框架,和我们之前使用过的DBUtils风格非常接近。

Spring AOP之基于注解的AOP

基于注解AOP步骤

  1. 将目标类和切面类加到IOC容器中。@Component
  2. 告诉Spring哪个是切面类。@Aspect
  3. 在切面类中使用五个通知注解中的这些通知方法都何时运行
  4. 开启基于AOP注解功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<bean id="mathCalculator" class="xyz.lyhcc.calculate.MathCalculator"></bean>
<bean id="loggerUtils" class="xyz.lyhcc.logger.LoggerUtils"></bean>
<bean id="validAspect" class="xyz.lyhcc.logger.ValidAspect"></bean>


<aop:config>
<aop:pointcut expression="execution(* xyz.lyhcc.calculate.MathCalculator.*(int,int))" id="glabalPointcut"/>
<aop:aspect ref="loggerUtils">
<aop:before method="logStart" pointcut-ref="glabalPointcut"/>
<aop:after-returning method="logFinished" pointcut-ref="glabalPointcut" returning="result"/>
<aop:after-throwing method="logError" pointcut-ref="glabalPointcut" throwing="exception"/>
<aop:after method="logFinal" pointcut-ref="glabalPointcut"/>
<aop:around method="aroundMethod" pointcut-ref="glabalPointcut"/>
</aop:aspect>

<aop:aspect ref="validAspect">
<aop:before method="logStart" pointcut-ref="glabalPointcut"/>
<aop:after-returning method="logFinished" pointcut-ref="glabalPointcut" returning="result"/>
<aop:after-throwing method="logError" pointcut-ref="glabalPointcut" throwing="exception"/>
<aop:after method="logFinal" pointcut-ref="glabalPointcut"/>

</aop:aspect>

</aop:config>

脚下留心
注解: 快速方便
配置: 功能完善
重要的用配置,不重要的使用注解


Spring AOP引入之Java动态代理打印日志

概述

使用动态代理使得在不影响打印日志的类的情况下进行日志打印,也就解耦业务逻辑和日志打印

Spring AOP

AOP(Aspect Oriented Programming)

面向切面编程:基于OOP(Object Oriented Programing基础之上的编程思想)
指在程序运行期间,将某段代码动态的切入到指定的位置进行运行的编程方式

SpringIOC总结

IOC是一个容器,帮我们管理所有的组件

  • 依赖注入 @autowired,自动赋值
  • 某个组件要使用Spring提供的更多功能(IOC,AOP)必须加入到容器中

Spring/Spring的单元测试

使用步骤

  1. 导包: Spring单元测试包spring-test-4.0.0.RELEASE.jar
  2. @ContextConfiguration(locations=””)来指定Spring的配置文件
  3. @RunWith指定用哪种驱动进行单元测试,默认JUnit

    @RunWith(SpringJUnit4ClassRunner.class)
    使用Spring的单元测试模块来执行标了@Test的测试方法
    好处是不需要获取Bean

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @ContextConfiguration(locations="classpath:ioc.xml")
    @RunWith(SpringJUnit4ClassRunner.class)
    public class SpringIOCTest {
    ApplicationContext ioc = null;

    @Autowired
    BookServlet bookServlet;

    @Test
    public void test() {
    System.out.println("--"+bookServlet);
    }
    }

Spring IOC实验

实验1:通过IOC容器创建对象,并为属性赋值★

HelloWorld 实现

实验2:根据bean的类型从IOC容器中获取bean的实例★

如果IOC容器这个类型的bean有多个,查找会报错
报错org.springframework.beans.factory.NoUniqueBeanDefinitionException

1
2
3
4
5
6
      /*Person bean = ioc.getBean(Person.class);
System.out.println(bean);
*/
// 指定类之后不需要强转
Person bean = ioc.getBean("person02", Person.class);
System.out.println(bean);
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×