(1) IOC 控制反转
所谓的控制反转就是应用本身不负责依赖对象的创建和维护,依赖对象的创建及维护是由
外部容器负责的(spring是外部容器之一)。这样控制权就由应用转移到了外部容器,控制权
的转移就是所谓的反转。
实例代码:
    //普通
    public class PersonServiceBean {
        private PersonDao personDao = new PersonDaoBean();
 
        public void save(Person person) {
            personDao.save(person);
        }
    }
    //IOC方式
   public class PersonServiceBean {
        private PersonDao personDao;
        //通过构造器参数,让容器把创建好的依赖对象注入进PersonServiceBean,当然也可以用setter的方式进行注入
        public PersonServiceBean(PersonDao personDao) {
            this.personDao = personDao;
        }

        public void save(Person person) {
            personDao.save(person);
        }
    }
所谓依赖注入(Dependency Injection)就是指:在运行期间,由外部容器动态地将依赖对象注入到组件中。
(2)Spring的好处
  • 降低组件之间的耦合度;
  • 提供了很多服务,事务管理服务,spring core核心服务,持久化服务等等。事务管理方面,不需要我们手工控制事务,也需要手动的去处理事务的传播行为;
  • 容器提供单例模式支持,不需要再编写实现代码;
  • AOP技术,很容易实现权限拦截,运行期监控等功能;
  • 提供了很多的辅助类,如JdbcTemplate,HibernateTemplate
  • 提供了主流应用框架集成的支持,如hibernate,mybatis
(3)轻量级和重量级
主要看它使用了多少服务,使用的服务越多,容器要为普通java对象做的工作越多,必然会影响到应用的发布时间或者是运行性能;
(4)入门知识点
    实例化Spring容器
    ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"bean.xml"});
    Spring的配置文件可以指定多个,通过数组传入多个配置文件
spring是如何实例化bean的:
  1. 解析配置的xml文件,获取到beans节点下面的bean
  2. 将bean装入集合,对外提供getBean方法,通过反射技术,Class.forName('xxx').newInstance()方法来获取到bean对象的实例
/**
* 读取xml配置文件
* @param filename
*/
private void readXML(String filename) {
SAXReader saxReader = new SAXReader();
Document document=null;
try{
URL xmlpath = this.getClass().getClassLoader().getResource(filename);
document = saxReader.read(xmlpath);
Map<String,String> nsMap = new HashMap<String,String>();
nsMap.put("ns","http://www.springframework.org/schema/beans");//加入命名空间
XPath xsub = document.createXPath("//ns:beans/ns:bean");//创建beans/bean查询路径
xsub.setNamespaceURIs(nsMap);//设置命名空间
List<Element> beans = xsub.selectNodes(document);//获取文档下所有bean节点
for(Element element: beans){
String id = element.attributeValue("id");//获取id属性值
String clazz = element.attributeValue("class"); //获取class属性值
BeanDefinition beanDefine = new BeanDefinition(id, clazz);
XPath propertySub = element.createXPath("ns:property");
propertySub.setNamespaceURIs(nsMap);
List<Element> propertiesElement = propertySub.selectNodes(element);
for (Element property : propertiesElement) {
String name = property.attributeValue("name");
String ref = property.attributeValue("ref");
String value = property.attributeValue("value");
// System.out.println(name + "==" + ref);
beanDefine.getProperties().add(new PropertyDefinition(name, ref,value));
}
beanDefines.add(beanDefine);
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 完成bean的实例化
*/
private void instanceBeans() {
for(BeanDefinition beanDefinition : beanDefines){
try {
if(beanDefinition.getClassName()!=null && !"".equals(beanDefinition.getClassName().trim()))
sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
} }
是如何依赖注入bean的:
     3.   在每个bean对应的java对象中,有需要注入的bean的set方法,通过Introspector.getBeanInfo获取到被注入bean对象的属性值,与配置文件中配置的bean进行匹配,如果匹配上通过pDescriptor.getWriteMethod方法,反射的方式将匹配到的bean注入到属性中去。
/**
* 为bean对象的属性注入值
*/
private void injectObject() {
for(BeanDefinition beanDefinition : beanDefines) {
Object bean = sigletons.get(beanDefinition.getId());
try {
if(null != bean) {
//得到bean的属性集合(<bean id="personDao" class="com.test.dao.impl.PersonDaoImpl" />)
PropertyDescriptor[] pd = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();//包含class属性
for(PropertyDefinition propertyDefinition : beanDefinition.getProperties()) {//配置文件中用户定义的bean属性
for(PropertyDescriptor pDescriptor : pd) {
if(propertyDefinition.getName().equals(pDescriptor.getName())) {
Method setter = pDescriptor.getWriteMethod();//获取属性的setter方法
if(null != setter) {
Object value = null;
if(propertyDefinition.getRef() != null && !propertyDefinition.getRef().trim().equals("")) {
value = sigletons.get(propertyDefinition.getRef());
}else {
value = ConvertUtils.convert(propertyDefinition.getValues(), pDescriptor.getPropertyType());//注入基本类型的值
}
setter.setAccessible(true);//如果setter方法是private的话,invoke会报错,需要设置
setter.invoke(bean, value);//把引用对象注入到属性
}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
实例化bean的方式有三种:
  1. 构造函数(用的最多)
  2. 静态工厂
  3. 实例工厂
bean的作用域:
  • singleton(默认):在spring ioc容器中一个bean定义只有一个实例对象,默认情况下会在容器启动的时候初始化,如果需要延迟初始化,需要在配置bean的时候加上lazy_init="true",这样只有在获取的时候才会初始化,对单个bean <bean id="person" class="com.test.bean.Person" lazy-init="true">,容器中所有bean都延迟加载<beans default-lazy-init="true">
  • prototype:每次从容器获取新的bean对象 <bean id="person" class="com.test.bean.Person" scope="prototype">,在getBean的时候进行实例化
bean的生命周期:
    默认情况下容器启动,AbstractApplicationContext中给出了一个close方法,
    其说明是Close this application context, destroying all beans
    AbstractApplicationContext ctx =  new ClassPathXmlApplicationContext(new String[]{"bean.xml"});
    ctx.close();
依赖注入手工装配或自动装配,自动装配会产生未知情况,不利于开发)
  • set属性的方式注入bean:(可以被多个bean同时使用)
      <bean id="personService" class="com.test.service.impl.PersonServiceImpl">
          <property name="personDao" ref="personDao"></property> 
                <!-- name是指要注入的属性,ref对应要注入的bean的名称,通过反射技术将bean设给了属性 -->
         </bean>
  • 内部bean的方式注入(只可以被这一个bean使用)
  • 使用构造器注入
          通过 constructor-arg 来注入
  • 使用Field注入(用于注解方式)
    1. 引入jar文件 common.annotations.jar
    2. 在xml添加配置如下
       命名空间  xmlns:context="http://www.springframework.org/schema/context"
       schema

          http://www.springframework.org/schema/context


  • 打开注解 <context:annotation-config />,这个配置隐式注册了多个对注释进行解析处理的处理器
  • 使用@Autowired或@Resource注解方式进行装配。区别在于:@Autowired默认按类型装配,
        @Resource默认按名称装配。建议使用Resource,这个是jdk提供的注解。
        自定义一个注解,该注解可用于set方法和字段上面,供处理器处理,将bean注入到字段或set方法中
package junit.test;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface TydicResource {
/**
* Retention(保留)注解说明,这种类型的注解会被保留到那个阶段. 有三个值:
* 1.RetentionPolicy.SOURCE —— 这种类型的Annotations只在源代码级别保留,编译时就会被忽略
* 2.RetentionPolicy.CLASS —— 这种类型的Annotations编译时被保留,在class文件中存在,但JVM将会忽略
* 3.RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用.
*
* Target(注解的作用目标)
*/
String name() default ""; }
package com.test.service.impl;

import javax.annotation.Resource;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service; import junit.test.TydicResource; import com.test.dao.PersonDao;
import com.test.service.PersonService; @Service("personService") @Scope("prototype")
public class PersonServiceImpl extends Object implements PersonService { // @TydicResource(name="xgw")<!-- 注解通过name寻找到bean注入 -->
@TydicResource
// @Resource
public PersonDao personDao; public PersonDao getPersonDao() {
return personDao;
}
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public void add() {
personDao.add();
}
}

查看set方法和field上是否加了注解

/**
* 通过注解方式注入bean
* 仿 注解处理器代码
*/
private void annotationInjectObject() {
for(String beanName : sigletons.keySet()) {
Object bean = sigletons.get(beanName);
if(null != bean) {
try {
PropertyDescriptor[] pd = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();//定义的javabean的属性集合
for(PropertyDescriptor pDescriptor : pd) {
Method setter = pDescriptor.getWriteMethod(); //属性的set方法
if(null != setter && setter.isAnnotationPresent(TydicResource.class)) {
TydicResource resource = setter.getAnnotation(TydicResource.class);//是否存在这个注解
Object value = null;
if(resource.name()!=null && !"".equals(resource.name())) {//注解中标明name属性
value = sigletons.get(resource.name());
}else {
value = sigletons.get(pDescriptor.getName());
if(value == null) { //如果在属性中也没有找到,就按类型去寻找
for(String key : sigletons.keySet()) {
/**
* isAssignableFrom
* either the same as, or is a superclass or * superinterface of, the class or interface
* 这个属性的类型如果是该磊的接口或者父类或者就是该类的话,返回true
*/
if(pDescriptor.getPropertyType().isAssignableFrom(sigletons.get(key).getClass())) {
value = sigletons.get(key);
break;
}
}
}
}
setter.setAccessible(true);
setter.invoke(bean, value);
}
} Field[] fields = bean.getClass().getFields();
for(Field field : fields) {
TydicResource resource = field.getAnnotation(TydicResource.class);//是否存在这个注解
Object value = null;
if(resource.name()!=null && !"".equals(resource.name())) {//注解中标明name属性
value = sigletons.get(resource.name());
}else {
value = sigletons.get(field.getName());
if(value == null) { //如果在属性中也没有找到,就按类型去寻找
for(String key : sigletons.keySet()) {
if(field.getType().isAssignableFrom(sigletons.get(key).getClass())) {
value = sigletons.get(key);
break;
}
}
}
}
field.setAccessible(true);
field.set(bean, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
自动扫描
spring2.5以后引入组件自动扫描机智,可以在类路径下寻找标注了
@Component 泛指组件,可通用
@Service         用于标注业务层组件
@Controller    用于标注控制层组件(如action)
@Respostory   用于标注数据访问组件dao层
注解的类,纳入到spring容器中管理

在配置文件中添加 <context:component-scan base-package="com.test.*" />,base-package为需要被扫描的包路径,
有了 <context:component-scan base-package="com.test.*" />配置之后就可以将<context:annotation-config />去掉,
前者注册的处理器包含了后者的。
由于spring初始化的时候采用的是单例,如果需要实现多个bean的话,可以加@Scope("prototype")来改变。
@PostConstruct   默认初始化方法
@PreDestroy
(4)AOP
使用Proxy创建代理对象的时候,目标对象必须实现一个接口,面向接口的时候才能使用Proxy创建代理对象。
 
joinpoint(连接点)
    被拦截的方法,需要被处理的可以被看做连接点(joinpoint),在spring中只支持方法类型的连接点,实际上连接点还可以是field或类构造器
pointcut(切入点)
    是指所有要被拦截的joinpoint定义
weave(织入):
    指将aspect应用到target对象并导致proxy对象创建的过程叫织入
Introdunction(引入):
    在不修改代码的情况下,在运行期动态的添加方法或field
aspect(切面):
    是指对横切性关注点的抽象,就像类是对实体的抽象一样。    
抽象过程的体现
package com.test.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import com.test.service.impl.PersonServiceImpl; public class JDKProxyFactory implements InvocationHandler {
private Object targetObject; public Object createProxyInstance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
PersonServiceImpl personServiceImpl = (PersonServiceImpl) this.targetObject;
Object result = null;
if(personServiceImpl.getUser()!=null) {
result = method.invoke(targetObject, args);
} return result;
}
}
package com.test.aop;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import com.test.service.impl.PersonServiceImpl; public class CglibProxyFactory implements MethodInterceptor {
private Object targetObject;//代理的目标对象 public Object createProxyInstance(Object targetObject) {
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer();//该类用于生成代理
/**
* cglib创建的代理,是目标对象的子类,能够复制非final修饰的所有方法
*/
enhancer.setSuperclass(this.targetObject.getClass());//设置父类
enhancer.setCallback(this);//设置回调用对象本身
return enhancer.create();
} @Override
public Object intercept(Object proxy, Method method, Object[] aobj,
MethodProxy methodproxy) throws Throwable {
PersonServiceImpl personServiceImpl = new PersonServiceImpl();
Object result = null;
if(personServiceImpl.getUser() != null) {
result = methodproxy.invoke(targetObject, aobj);
}
return result;
} }
Spring AOP编程
如果Spring检测到类实现了接口,则会用jdk提供的Proxy动态代理技术进行拦截,如果类没有实现接口,则会用cglib的方式进行创建代理对象。
切面:@Aspect
声明一个切入点:@Pointcut("executor(* com.test.service..*.*(..))")
各种通知:@Before,@AfterReturning,@After,@AfterThrowing
@Around     需要加上切入点("anyMethod()"),才可以。
首先默认会拦截切点后面所有指定的方法
同时可以再添加限制条件,进行拦截限制
  
(5)事务管理
引入命名空间:xmlns:tx="http://www.springframework.org/schema/tx
//配置数据源
  • 直接配置在spring的配置文件中
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
   <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
   <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
   <property name="username" value="root"></property>
   <property name="password" value="root"></property>
  </bean>
  • 配置在配置文件(db.properties)中
采用第一种方式即可,配置文件方式了解即可
  //配置事务管理器
  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"></property>
  </bean>
//打开事务管理
<tx:annotation-driven transaction-manager="txManager" />
 
运行期(RuntimeException unchecked)异常会进行回滚
可以通过设置,让RuntimeException异常不回滚
可以通过设置,让checked的异常回滚
 
由于事务会影响性能,所以如果不需要进行事务管理的话,就要声明该方法不需要事务管理,比如说查询列表或者查情详情,事务会被挂起,在该方法调用结束后,原先的事务会恢复执行。@Transactional(propagation=Propagation.NOT_SUPPORTED)
 
XML方式配置事务
建议使用注解方式,但是在实际项目中运用大多是xml方式。
 
数据库事务隔离级别
 

Spring框架的初步学习的更多相关文章

  1. Spring框架-AOP详细学习[转载]

    参考博客:https://blog.csdn.net/qq_22583741/article/details/79589910#4-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85% ...

  2. Spring框架零基础学习(一):IOC|DI、AOP

    文章目录 一.IDEA创建Spring项目 二.Spring: IOC和DI 三.Spring: AOP 参考链接: HOW2J.CN:Spring idea创建一个spring项目 一.IDEA创建 ...

  3. 学习Spring框架等技术的方向、方法和动机

    学习Spring框架最早学习Spring框架是在大二的时候,当时看了几本书,看了一些视频,主要是传智播客的.更多的,还是写代码,单独写Spring的,也有与Struts和Hibernate等框架整合的 ...

  4. 一文深入浅出学习Spring框架系列,强烈推荐

    本系列主要介绍Spring框架整体架构,Spring的核心IOC,AOP的案例和具体实现机制:以及SpringMVC框架的案例和实现机制.@pdai 相关文章 首先, 从Spring框架的整体架构和组 ...

  5. Spring框架学习一

    Spring框架学习,转自http://blog.csdn.net/lishuangzhe7047/article/details/20740209 Spring框架学习(一) 1.什么是Spring ...

  6. 老周的ABP框架系列教程 -》 一、框架理论初步学习

    老周的ABP框架系列教程 -- 一.框架理论初步学习   1. ABP框架的来源与作用简介 1.1  简介 1.1.1       ABP框架全称为"ASP.NET Boilerplate ...

  7. Spring框架学习之第2节

    传统的方法和使用spring的方法 使用spring,没有new对象,我们把创建对象的任务交给了spring的框架,通过配置用时get一下就行. 项目结构 applicationContext.xml ...

  8. Spring框架学习 - 配置

    [资料] ★★☆ Spring 中提供一些Aware相关接口,像是BeanFactoryAware. ApplicationContextAware.ResourceLoaderAware.Servl ...

  9. 深入浅出学习Spring框架(四):IoC和AOP的应用——事务配置

    在前文 深入浅出学习Spring框架(一):通过Demo阐述IoC和DI的优势所在. 深入浅出学习Spring框架(三):AOP 详解 分别介绍了Spring的核心功能——IoC和AOP,光讲知识远远 ...

随机推荐

  1. static与线程安全 -摘自网络

    在.Net中,Static会经常和线程的东西扯在一起.写的代码是不是线程安全呢?好多程序员都在想,不过,有时候随便就放过了.真正出问题的时候再想.其实,如果程序员一开始就明白这里面的机制,也许,编写的 ...

  2. 微软2016校园招聘4月在线笔试 ABC

    题目链接:http://hihocoder.com/contest/mstest2016april1/problems 第一题:输入N,P,W,H,代表有N段文字,每段有ai个字,每行有⌊W/S⌋个字 ...

  3. hdoj 5522 Numbers

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5522 水题:暴力过 #include<stdio.h> #include<strin ...

  4. 如何解决Python脚本在Linux和Windows上的格式问题

    python是一种对缩进有严格要求的语言, Python脚本可以使用非常多的工具进行编写,笔者在Linux系统使用JEdit进行Python脚本编写,由于在Linux编写脚本比较痛苦,比如想一眼看出相 ...

  5. hdu4433 locker

    暴力dp.. dp[i][j][k] 表示 前i位完全匹配 j 表示i+1位 k表示i+2位 枚举j k #include<iostream> #include<cstdio> ...

  6. linux内核奇遇记之md源代码解读之四

    linux内核奇遇记之md源代码解读之四 转载请注明出处:http://blog.csdn.net/liumangxiong 运行阵列意味着阵列经历从无到有,建立了作为一个raid应有的属性(如同步重 ...

  7. Python自动安装第三方类库

    Python在使用过程中会用到大量的第三方库,逐一手工去下载.安装比较繁琐.可以配置第三方镜像源并使用pip进行自动安装.这里推荐选择豆瓣的镜像源:http://pypi.douban.com/sim ...

  8. SecureCRT学习之道:SecureCRT经常使用快捷键设置与字体设置方法

    1:假设不想每次登陆都输入password,能够在你打开的session里邮件session option->login action 选中automate logon 双击ogin 和assw ...

  9. 《编程导论(Java)&#183;2.1.3改写(override)》

    <编程导论(Java)·2.1.3改写(override)>,收集override内容. 方法改写(method overriding)是指对于父类定义的一个实例方法,同意子类提供自己的实 ...

  10. Java基础知识强化之IO流笔记56:IO流练习之 登录注册IO版

    1.  登录注册IO版的Java项目框架,如下: 2. 具体代码实现: (1)User.java(cn.itcast.game): package cn.itcast.pojo; /** * 这是用户 ...