重学Spring


一、Spring介绍

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。

​ **Spring的核心是控制反转IoC)和面向切面(AOP)。**简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。

1.1 控制反转(IOC/DI)

控制反转(Inversion of Control),就是应用本身不负责对象的创建和维护,对象和依赖对象创建完全交给Spring的容器去管理和维护,这个权利反转给容器

项目中分层开发,学Spring之前bean都是我们自己创建;我们自己创建DaoImpl();带来了很大的耦合性,项目不好维护,测试成本也高

依赖注入(DI)IOC的别名 ,

控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)”。他的这个答案,实际上给出了实现IOC的方法:注入。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

1.2 面向切面编程(AOP)

那么AOP也是一种编程思想,作用是在不改变原始设计的基础上为其进行功能增强。

1.3 Spring的其他功能

image-20220911172328464

Core Container(核心容器):

  • Beans:负责Bean工厂中Bean的装配,所谓Bean工厂即是创建对象的工厂,Bean的装配也就是对象的创建工作;
  • Core:这个模块即是负责IOC(控制反转)最基本的实现;
  • Context:Spring的IOC容器,因大量调用Spring Core中的函数,整合了Spring的大部分功能。Bean创建好对象后,由Context负责建立Bean与Bean之间的关系并维护。所以也可以把Context看成是Bean关系的集合;
  • SpEl:即Spring Expression Language(Spring表达式语言);

Data Access/Integration(数据访问/集成):

  • JDBC:对JDBC的简单封装;
  • ORM:支持数据集成框架的封装(如Mybatis,Hibernate);
  • OXM:即Object XML Mapper,它的作用是在Java对象和XML文档之间来回转换;
  • JMS:生产者和消费者的消息功能的实现;
  • Transations:事务管理,不多BB;

Web:

  • WebSocket:提供Socket通信,web端的的推送功能;
  • Servlet:Spring MVC框架的实现;
  • Web:包含web应用开发用到Spring框架时所需的核心类,包括自动载入WebApplicationContext特性的类,Struts集成类、文件上传的支持类、Filter类和大量辅助工具类;
  • Portlet:实现web模块功能的聚合(如网站首页(Port)下面可能会有不同的子窗口(Portlet));

AOP:

  • 面向切面;

Aspects:

  • 同样是面向切面的一个重要的组成部分,提供对AspectJ框架的整合;

Instrumentation(设备):

  • 相当于一个检测器,提供对JVM以及对Tomcat的检测;

Messaging(消息):

  • Spring提供的对消息处理的功能;

Test(测试):

  • 我们在做单元测试时,Spring会帮我们初始化一些测试过程当中需要用到的资源对象

二、环境搭建

1、jar包引入
2、创建spring的配置文件,默认名称叫ApplicationContext.xml
  <?xml version="1.0" encoding="UTF-8"?>
		<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    </beans>
     
3、创建bean
  public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
      System.out.println("user被保存了");
    }
	}

4、Spring配置
  <bean id="userDao" class="com.test.spring.dao.impl.UserDaoImpl">
  </bean>
    
5、创建Spring的容器
  @Test
	public void test() {
		//初始化spring容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext("ApplicationContext.xml");
		//获得bean
		UserDao userDao = (UserDao) ctx.getBean("userDao");
		userDao.save();
	}

三、Bean的创建方式

3.1 使用构造器创建

1、使用构造器方式创建bean,要求bean必须要有默认的构造器,这是工作中最常用的方式。
    public class User {
      public User() {
      }
    }
2、配置bean
  <bean id="user" class="com.test.spring.model.User"></bean>

3.2 静态工厂方式创建

1、提供静态工厂
  public class FactoryBean {
    /**
     * 必须是静态方法
     * @return
     */
    public static User createUser(){
      return new User();
    }
  }
2、配置bean
  <!-- id:唯一标识
		class:静态工厂的类,factory-method:静态工厂的方法
	-->
	<bean id="user" class="com.test.spring.factory.FactoryBean" factory-method="createUser"></bean>

3.3 实例工厂方式创建

1、实例工厂
  public class FactoryBean1 {
    public User createUser(){
      return new User();
    }
  }
2、配置bean
  <!-- 通过Spring来定义实例工厂 -->
	<bean id="factoryBean" class="com.rl.spring.factory.FactoryBean1"></bean>
	<!-- 指定要创建的bean
		factory-bean:指定实例工厂类,factory-method:工厂的创建bean的方法
	-->
	<bean id="user" factory-bean="factoryBean" factory-method="createUser"></bean>

四、延迟加载

所有的bean默认情况下,非延迟加载的,是spring的容器创建的时候就把bean给创建出来了,我们getBean的时候直接从容器中去拿这个Bean就可以了。

是否延迟加载由lazy-init来控制,默认是false,如果变成true就在getBean的时候去创建user。

<bean id="lazyInitBean" class="com.javacode2018.lesson001.demo11.LazyInitBean" lazy-init="true"/>

五、Bean的作用域

默认情况下,bean都是单例的,是容器初始化的时候被创建的,就这么一份

Scope:singleton单例,prototype多例,默认使用singleton

如果是singleton我们可以设置非延迟加载(容器初始化时创建bean)和延迟加载(getBean的时候才创建)方式创建bean

如果是prototype我们没得选择只能是延迟加载方式创建(getBean的时候才创建)

六、Bean的生命周期

Bean的生命周期和容器的生命周期一致,容器被创建bean就被创建,容器销毁bean就被销毁;创建是和销毁时,会调用指定的方法

1、方法
  public class User {
    public User() {
    }
    public void init(){
		  System.out.println("我出来了");
	  }
	  public void destroy(){
		  System.out.println("20年后又是一条好汉");
	  }
}

2、Bean配置
  <!-- 
		init-method:bean被创建时调用,destroy-method:bean被销毁时调用
	 -->
	<bean id="user" class="com.test.spring.model.User" init-method="init" destroy-method="destroy"></bean>

七、依赖注入

7.1 属性注入(set注入)

7.1.1 常量注入

<!--  bean的常量注入-->
<bean id="user" class="com.test.spring.model.User">
  
  <!-- property:class里面的属性,name:属性名-->
  <property name="userId" value="1"></property>
  <property name="username" value="renliang"></property>
  <property name="password" value="123"></property>
</bean>

7.1.2 集合注入

1、对象
  @Data
  public class CollectionInjection {
    private Set<String> set;
    private List<String> list;
    private Map<String, String> map;
    private Properties prop;
  }
2、注入
  <bean id="ci" class="com.rl.spring.model.CollectionInjection">
		<property name="set">
			<set>
				<value>football</value>
				<value>basketball</value>
			</set>
		</property>
		<property name="list">
			<list>
				<value>male</value>
				<value>female</value>
			</list>
		</property>
		<property name="map">
			<map>
				<entry key="key1" value="value1"></entry>
				<entry key="key2" value="value2"></entry>
			</map>
		</property>
		<property name="prop">
			<props>
				<prop key="name">任亮</prop>
				<prop key="job">讲师</prop>
			</props>
		</property>
	</bean>  

7.1.3 外部bean注入(对象)

1、外部Bean注入:必须提供set方法
    public class UserServiceImpl implements UserService {
      private UserDao userDao;
      /**
       * 外部bean的方式注入,必须提供要注入的bean的set方法
       * @param userDao
       */
      public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
      }

      @Override
      public void save() {
        userDao.save();
      }
    }
2、配置
    <!-- 定义UserDao的bean -->
    <bean id="userDao" class="com.test.spring.dao.impl.UserDaoImpl"></bean>
    <!-- 定义Service的bean -->
    <bean id="userService" class="com.test.spring.service.impl.UserServiceImpl">
      <!-- 通过属性方式注入
        name:bean的属性名
        ref:要注入的bean
       -->
      <property name="userDao" ref="userDao"></property>
    </bean>

7.1.4 内部bean注入(对象)

内部bean不能其他bean注入

1、外部Bean注入:必须提供set方法
    public class UserServiceImpl implements UserService {
      private UserDao userDao;
      /**
       * 外部bean的方式注入,必须提供要注入的bean的set方法
       * @param userDao
       */
      public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
      }

      @Override
      public void save() {
        userDao.save();
      }
    }
2、配置
    <bean id="userService" class="com.rl.spring.service.impl.UserServiceImpl">
      <property name="userDao">
        <bean class="com.rl.spring.dao.impl.UserDaoImpl"></bean>
      </property>
    </bean>

7.2 构造器注入

7.2.1 常量注入

<!-- 构造器方式注入 -->
<bean id="user" class="com.test.spring.model.User">
		<!-- 
        index:构造方法的参数的索引顺序
        type:构造方法的参数的类型(不是必须 的)
        value:值
		 -->
		<!-- <constructor-arg index="0" type="java.lang.Integer" value="2"/>
		<constructor-arg index="1" type="java.lang.String" value="renliang"/>
		<constructor-arg index="2" type="java.lang.String" value="666"/> -->
		<constructor-arg index="0"  value="2"/>
		<constructor-arg index="1"  value="renliang"/>
		<constructor-arg index="2"  value="666"/>
	</bean>

7.2.2 对象注入

public class UserServiceImpl implements UserService {
	private UserDao userDao;
	
	public UserServiceImpl() {
	}
	
	public UserServiceImpl(UserDao userDao) {
		super();
		this.userDao = userDao;
	}

	@Override
	public void save() {
		userDao.save();
	}
}

<!-- 定义UserDao的bean -->
	<bean id="userDao" class="com.test.spring.dao.impl.UserDaoImpl"></bean>
	<!-- 定义UserService的Bean -->
	<bean id="userService" class="com.test.spring.service.impl.UserServiceImpl">
		<!-- 通过构造器的方式指定注入的bean
			   type:指定UserDao接口,不要指定实现类
			   ref:就是要注入的bean
		 -->
		<constructor-arg index="0" type="com.test.spring.dao.UserDao" ref="userDao"/>
	</bean>

7.3 注解方式注入

引入jar包、引入约束文件、开启注解的驱动

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.2.xsd">

	<!-- 开启注解的驱动 -->
	<context:annotation-config/>
	
	<bean id="userDao" class="com.rl.spring.dao.impl.UserDaoImpl"></bean>
	
	<bean id="userService" class="com.rl.spring.service.impl.UserServiceImpl"></bean>
</beans>

7.3.1 Resource注解

1、Resource时java的注解

2、既可以加在方法上也可以加在属性上

3、默认按照name进行匹配的,如果不写,默认是变量名,如果找不到会按照Type进行匹配,再找不到就会报错

4、加在方法上,会先按照(属性名、set后面小写名、入参名)进行匹配,未匹配则会按照type进行匹配;

5、一旦指定了name,就不会按照type进行匹配

7.3.2 Autowird注解

1、Autowird是Spring提供的注解

2、既可以加在方法上也可以加在属性上

3、Autowird默认是按照Type进行匹配的,如果接口有多个实现的话,会先根据默认名进行匹配,匹配不上则报错;最好配合Qualifier显示的指定

八、Spring的扫描器

用来扫描管理Bean的

实际项目如果很大就会出现大量配置,我们使用扫描器可以解决这个问题

扫描器扫描带有@Controller,@Service, @Repository,@Component的类

@Controller:控制层的类

@Service:服务层的类

@Repository:数据层的类

@Component:无法分层的类上

以上注解标注的类的bean的id默认类名的首字符小写

九、Spring整合Junit

/**
 * @RunWith:指定spring对junit提供的一个运行器
 * @ContextConfiguration:指定spring配置文件位置
 * @author renliang
 *
 */
@RunWith(value=SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:ApplicationContext.xml"})
public class TestSpring1 {

	/**
	 * 在junit的bean中注入UserService
      *  即UserService的实现类一定加入了4种注解之一,创建的对象赋值给了UserService
	 */
	@Autowired
	UserService userService;
	
	@Test
	public void test2() {
		userService.save();
	}
}

十、AOP

十一、JdbcTemplate

1、引入jdbc的包
  
2、配置数据源
  <!-- 数据源配置 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		<property name="url" value="jdbc:mysql://localhost:3306/spring3.2_10"></property>
		<property name="username" value="root"></property>
		<property name="password" value="root"></property>
		<!-- 初始化的连接数 -->
		<property name="initialSize" value="1"></property>
		<!-- 连接池的最大连接数-->
		<property name="maxActive" value="5"></property>
		<!-- 最大的空闲的连接数 -->
		<property name="maxIdle" value="2"></property>
		<!-- 最小的空闲连接数 -->
		<property name="minIdle" value="1"></property>
	</bean>
    
3、使用
    public class UserDaoImpl implements UserDao {
      private DataSource dataSource;
      private JdbcTemplate jt;

      public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        this.jt = new JdbcTemplate(dataSource);
      }

      @Override
      public void saveUser(User user) {
        String sql = "insert into t_user values(null, ?, ?)";
        jt.update(sql, new Object[]{user.getUsername(), user.getPassword()});
      }

      @Override
      public void updateUser(User user) {
        String sql = "update t_user set username = ?, password=? where user_id = ?";
        jt.update(sql, new Object[]{user.getUsername(), user.getPassword(), user.getUserId()});
      }

      @Override
      public User queryUserById(int userId) {
        String sql = "select * from t_user t where t.user_id = ?";
        User user = jt.queryForObject(sql, new Object[]{userId}, new UserRowMapper());
        return user;
      }

      @Override
      public List<User> queryUserAll() {
        String sql = "select * from t_user";
        List<User> userList = jt.query(sql, new UserRowMapper());
        return userList;
      }
	}  

十二、事务控制

12.1 什么是事物?

一荣俱荣,一损俱损,很多复杂的操作我们可以把它看成是一个整体,要么同时成功,要么同时失败。

事务的四个特征ACID:

原子性(Atomic):表示组成一个事务的多个数据库的操作的不可分割的单元,只有所有的操作成功才算成功,整个事务提交,其中任何一个操作失败了都是导致整个所有操作失败,事务会回滚。

一致性(Consistentcy):事务操作成功后,数据库所处的状态和业务规则一致。如果A账户给B账户汇100,A账户减去100,B加上100,两个账户的总额是不变的。

隔离性(islation):在多个数据库的操作相同的数据并发时,不同的事务有自己的数据空间,事务与事务之间不受干扰(不是绝对的)。干扰程度受数据库或者操作事务的隔离级别来决定,隔离级别越高,干扰就越低,数据的一致性越好,并发性就越差。

持久性(Druability):一旦事务提交成功,数据就被持久化到数据库,不可以回滚。


文章作者: superzqbo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 superzqbo !
评论
  目录