miracle just wanna be better

spring框架

2019-08-20
miracle

框架

spring mvc框架

servlet:只做三件事

  • 1.获取数据 n多个request.getParameter(“key”);
  • 2.调用业务
  • 3.根据业务结果做相应的跳转(重定向和转发) 根据业务的结果相应json数据到js客户端 spring mvc:
  • 1.获取数据 恭喜你,springmvc 帮你做了
  • 2.调用业务 程序员专注于做相应的业务
  • 3.根据业务结果做相应的跳转(重定向和转发) 恭喜你,springmvc 帮你做了

    mybatis框架

  • 原生jdbc 开发效率低,执行效率高 手洗衣服
  • 基于原生jdbc衍生出CommonDao 开发效率稍高 手工搓衣板
  • springjdbc是spring框架的产品 相同 品牌搓衣板
  • mybatis框架 开发效率继续提高 半自动洗衣机
  • hibernate框架 开发效率最高 全自动洗衣机

spring框架

原先对象的创建都是有程序员根据业务的需求来new对象,而且需要程序员管理对象之间的关系
用spring框架不但能帮程序员创建对象,而且还能管理对象之间的关系
对象之间的关系:依赖关系,组合关系(has a),继承关系(is a)
比如:
在UserServiceImpl类中需要UserDaoImpl的对象
UserServiceImpl依赖于UserDaoImpl
UserServiceImpl有一个UserDaoImpl
总结:框架就是用来提高开发效率,是程序员福音

spring框架: spring是一个开源的轻量级的应用开发框架,其目的用于企业级应用程序的开发,减少侵入(降低耦合)

解释几个必要的名词:

  • 开源:开放源代码,提供框架源代码
  • 轻量级:互相依赖越少,越轻量级
  • 减少侵入/降低耦合:高内聚,低耦合
  • 耦合的分类:
    1.无/零耦合:类和类之间没有任何关系
    2.抽象耦合:在本类中耦合的是另一个类的抽象(接口(推荐),抽象类(不推荐)
    面向接口编程,面向抽象编程
     //UserDao是UserDaoImpl的接口
     //UserDao是UserDao_OracleImpl的接口			 
 比如:public class UserServiceImpl{			          
			  private UserDao userDao;//还没有new,等下面返回一个userDao对象
			  public void setUserDao(UserDao  userDao){
			    this.userDao=userDao;
			  }
			  public Boolean addUser(){
				userDao.addUser();
			  }
	       }
  • 3.具体耦合:在本类中耦合的是另一个具体的类
 比如:public class UserServiceImpl{
          //UserDao是UserDaoImpl的接口
		  private UserDaoImpl userDao;
		  public Boolean addUser(){
			userDao.addUser();
		  }
      }
	  public class UserServiceImpl{
          //UserDao是UserDaoImpl的接口
		  private UserDao userDao=new UserDaoImpl();//直接new出对象
		  public Boolean addUser(){
			userDao.addUser();
		  }
      }

使用框架步骤

spring有很多内容,现阶段只涉猎:

  1. spring IOC 控制反转
  2. spring DI 依赖注入
  3. spring aop 面向切面编程
  4. spring jdbc 品牌搓衣板
  5. spring 声明式事务管理
  • spring IOC 控制反转 Inversion of Control(IOC),把new对象不放在具体类中new,把new对象的控制权反转到第三方spring容器中 去new对象

  • spring DI 依赖注入 Dependency Injection(DI),就是把spring容器中new

1.导入jar包

  • 方式一:
    手动拷贝jar到项目中,然后右键单击jar包–build jar
    spring-context.jar
    spring-aop.jar
    spring-beans.jar
    spring-core.jar
    spring-expression.jar
  • 方式二: 用maven下载jar包
	<!-- spring context依赖包 -->
  	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</artifactId>
		<version>4.3.7.RELEASE</version>
	</dependency>

2.创建清单文件:超级建议从开发文档中拷贝

原始清单文件:

	<?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.xsd">
	<bean id="..." class="...">
	<!-- collaborators and configuration for this bean go here -->
	</bean>
	<bean id="..." class="...">
	<!-- collaborators and configuration for this bean go here -->
	</bean>
	<!-- more bean definitions go here -->
	</beans>

修改清单文件:

    <?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.xsd">
		<!-- spring的清单文件,告知spirng容器要把谁实例化对象 -->
		<bean id="hello" class="com.tarena.ioc.Hello"></bean>
		
	</beans>

3.初始化spring容器

    ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"});

从spring容器中取出对象

    Hello hello=context.getBean("hello",Hello.class);

ioc容器实例化对象的若干常见错误:

有异常一定要先仔细阅读异常信息,针对eclipse mars2,及以前版本
如果有Caused by字样的异常信息,看最后的Caused by提示的信息

  1. Caused by: java.lang.ClassNotFoundException: com.tarena.ioc.Hello1 类没有发现异常,说明指定的类不存在
    建议: 按住ctrl键 ,把鼠标放在class属性所对对应的类上,如果出现下划线,说明类写对了
  2. id的名称必须唯一的
<bean id="hello" class=""/>

Bean name ‘hello’ is already used in this element 有相同的名称hello在Beans节点元素中

  1. 还有另一个中写法但不建议
  <bean name="hello" class="" />

原因是name中不能写一些特殊字符

  1. 指定的清单文件不存在
    不是运行的是src/java/resoureces/applicationContext.xml
    实际运行的是类路径中的applicationContext.xml
    Caused by: java.io.FileNotFoundException:
    class path resource [applicationContext1.xml]
    cannot be opened because it does not exist
  2. 容器中没有取出对象 No bean named ‘hello2’ available

spring

spring的原理:

启动spring容器:

ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"});
  • a.spring一定要正确加载和解析spring.xml文件
  • b.把applicationContext.xml中的bean节点的内容解析出来并存储给map集合
  • c.循环遍历map集合中的所有数据取出class属性对应的数据值,通过反射实例化对象
  • Object obj=Class.forName(“包名.类名”).newInstance();//实例化的是无参数构造
  • d.把创建完的对象存储到另一个map集合中,用bean的id作为key,new完的对象做为值,所谓spring容器就是一个map集合
  • e.如果有属性需要注入,spring框架就帮你注入数据

getBean api方法:

  • getBean(Class);//根据类型获取,必须容器中类型对象唯一
  • getBean(String);//根据id从容器中获取对象,需要强制转换
  • getBean(String,Class);//根据id和类型同时确定一个容器中的一个对象

spring的配置/清单文件不智能提示(不能联网时):

要求D:/beans/spring-beans-4.3.xsd,文件真实存在

    <?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
		file:///D:/beans/spring-beans-4.3.xsd">
		<!-- spring的清单文件,告知spirng容器要把谁实例化对象 -->
		<bean id="hello" class="com.tarena.ioc.Hello"></bean>
		<bean id="hello1" class="com.tarena.ioc.Hello"></bean>
	</beans>

spring容器:

  1. 同一个类类型,可以实例化多次,但id的名称不能重复
    <bean id="hello" class="com.tarena.ioc.Hello"></bean>
	<bean id="hello1" class="com.tarena.ioc.Hello"></bean>
  1. 一个类的对象被spring容器实例化,可以通过getBean方法可以取多次

spring容器实例化和管理对象的四种方式:

  1. 通过无参数构造方式实例化对象(推荐,重要,用的最多) 注意:此种情况是spring帮你创建对象,并把对象放在spring容器中管理
    重要的前提,类中必须有一个无参数的构造
  <bean id="hello" class="com.tarena.ioc.Hello"></bean>

Caused by: java.lang.NoSuchMethodException: com.tarena.ioc.Hello.() 没有无参构造

  1. 静态工厂: 注意:此种情况不是spring帮你创建对象,是别的渠道创建的对象,交给spring管理
	<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.xsd">
		<!-- spring的清单文件,告知spirng容器要把谁实例化对象 -->
		<!-- 静态工厂
		   所谓的静态工厂,通过类的名字调用类中一个静态方法,
		   由静态方法生产一个对象,交给spring容器来管理
		 class属性的值,是一个抽象类或普通类
		 factory-method是抽象类中的一个静态方法
		 -->
		<bean id="calc" 
			  class="java.util.Calendar" 
			  factory-method="getInstance"></bean>	
	</beans>
  1. 实例工厂 注意:此种情况不是spring帮你创建对象,是别的渠道创建的对象,交给spring管理
    <!-- 实例工厂 
     所谓的实例工厂,是区分生产对象的方法不是静态方法
     先创建实例工厂对象if
     通过factory-bean和factory-method来调用非静态方法,以获得Hello的对象,并交给spring管理
     有两个对象
    -->
    <bean id="if" class="com.tarena.factory.InstanceFactory" ></bean>
	<bean id="hello1" 
	      factory-bean="if" 
	      factory-method="getObject"></bean>
    public class InstanceFactory {
		public Hello getObject(){
			return new Hello();
		}
    }
  1. spring工厂 注意:此种情况不是spring帮你创建对象,是别的渠道创建的对象,交给spring管理
    <!-- spring工厂 
      本应该实例化SpringFactory对象,但这个类实现了FactoryBean接口
      spring会自动调用getObject方法,方法返回的对象就是要交个spring管理的对象
    -->
  <bean id="hello2" class="cn.tedu.factory.SpringFactory"></bean>
public class SpringFactory implements FactoryBean<Hello>{
	@Override
	public Hello getObject() throws Exception {
		// TODO Auto-generated method stub
		return new Hello();
	}
	@Override
	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Hello.class;
	}
	@Override
	public boolean isSingleton() {
		// TODO Auto-generated method stub
		return true;
	}
}

结论:spring想要达到,用纯java能创建的对象,spring框架也可以创建和管理这些对象

单例设计模式:

就是对象在内存中永远只有一个对象
要求能独立手写出三个以上的单例写法

   /**
	 * 懒汉式,线程不安全
	 * @author Administrator
	 *
	 */
	public class Singleton1 {
		private static Singleton1 instance;
		private Singleton1(){
			
		}
		public static Singleton1 getInstance(){
			if(instance==null){
				instance=new Singleton1();
			}
			return instance;
		}
	}
	 /**
	 * 懒汉式,线程安全
	 * @author Administrator
	 *
	 */
	public class Singleton2 {
		private static Singleton2 instance;
		private Singleton2(){
			
		}
		public static synchronized Singleton2 getInstance(){
			if(instance==null){
				instance=new Singleton2();
			}
			return instance;
		}
	} 
	/**
	 * 饿汉式,线程不安全
	 * @author Administrator
	 *
	 */
	public class Singleton3 {
		private static Singleton3 instance=new Singleton3();
		private Singleton3(){
			
		}
		public static Singleton3 getInstance(){
			
			return instance;
		}
	}
	/**
	 * 饿汉式,变种
	 * @author Administrator
	 *
	 */
	public class Singleton4 {
		private static Singleton4 instance=null;
		static{
			instance=new Singleton4();
		}
		private Singleton4(){
			
		}
		public static Singleton4 getInstance(){
			
			return instance;
		}
	}

spring创建对象的是单例还是多例

  1. spring容器默认情况下,创建的对象是单例的 说明对象在容器中只有一个,可以从容器中取多次,对象的生命周期,跟容器的生命周期相同
  <bean id="hello" class="com.tarena.ioc.Hello"></bean>
  <!--等同于-->
  <bean id="hello" class="com.tarena.ioc.Hello" scope="singleton"></bean>
  1. spring的多例 scope=”prototype” 什么时候getBean,什么时候才实例化对象,并把对象返回给用户,对象的生命周期不是由spring容器掌控,由用户来掌控
    注意,在spring容器初始化的时候是不实例化对象的
  <bean id="hello" class="com.tarena.ioc.Hello" scope="prototype"></bean>

spring容器的生命周期:容器何时创建,何时销毁

何时创建:生命周期开始,之后自动调用init方法

    AbstractApplicationContext context =
				new ClassPathXmlApplicationContext("xxx.xml");
  • a.局部初始化 init是一个方法名称
	  <bean id="hello" class="com.tarena.ioc.Hello" init-method="init"></bean>
  • b.全局初始化
<beans  default-init-method="init"><beans>

何时销毁:生命周期结束,自动调用destroy方法context.close();

  • a.局部销毁 destroy是一个方法名称
	  <bean id="hello" class="com.tarena.ioc.Hello" destroy-method="destroy"></bean> 
  • b.全局销毁
	  <beans  default-destroy-method="destroy"><beans>

spring容器中的对象懒加载:

就是控制对象创建时机

  <bean id="hello" 
        class="com.tarena.ioc.Hello"
		scope="singleton"
		lazy-init="true"></bean>

虽然scop=”singleton”,但是如果懒加载为true,就是不在容器初始化的时候创建对象,而是在getBean的时候才创建对象,对象还是只有一个以后再getBean,始终是获取第一个次getBean时创建的对象

全局写法

  <beans default-lazy-init="true"></beans>

指定beans中的所有的bean都懒加载

在spring的配置文件中导入其他的spring的配置文件

	<beans>
		<import resource="services.xml"/>
		<import resource="resources/messageSource.xml"/>
		<import resource="/resources/themeSource.xml"/>
	</beans>

spring DI dependency injection依赖注入:

注入的方式:

  • setter方式注入
  • 构造函数注入

setter方式注入分类:

对象注入,单值注入,集合注入,表达式注入,空值注入

对象注入:

	<?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.xsd">
		
		<bean id="userDao" 
			  class="com.tarena.dao.impl.UserDaoImpl"></bean>
		<!-- 
		<bean节点用来告知spring实例化或管理对象
		<property节点 是用告知spring有对象的注入,相当于告知spring要管理对象的关系
		   name属性 其实对应的是 <bean class属性对应类中的setter方法
		   name="userDao" userDao->setUserDao
		   把name属性的值的第一个字母大写,前面加上set,构建一个字符串setUserDao
		   拿这个setUserDao字符串取UserServiceImpl类中寻找是否有此名称的方法
		   如果有set方法,就反射调用这个set方法
		   ref="userDao"  ref :reference 引用    要引用一个对象userDao
		   注意,ref引用的对象,一定是引自spring容器  userDao是容器中的一个唯一的id
		 -->      
		<bean id="userService" class="com.tarena.service.impl.UserServiceImpl">
			<!-- 对象注入 -->
			<property name="userDao" ref="userDao"></property>
		</bean>
	</beans>

值注入:

    <?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.xsd">
		<!-- 
		bean节点告知spring实例化管理对象
		property节点,告知spring做数据注入
		   name="age"   age->setAge
		   name="address"  address->setAddress
		   在ValueInject类中应该有两个set方法分别是setAge方法和setAddress方法
		   value="18"  ,双引号是数据的内容只是分隔符
			  value所对应的数据就是单值,注意不是从容器取的数据,只是一个固定值而已
		 -->
		<bean id="valueInject" 
			  class="com.tarena.value.ValueInject">
			<property name="age" value="18"></property>
			<property name="address" value="北京海淀巨山农场"></property>
		</bean>		
	</beans>

集合注入:(直接集合注入,间接集合注入)

  1. 直接集合注入: 特点:只能使用一次
    <?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:aop="http://www.springframework.org/schema/aop"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xmlns:p="http://www.springframework.org/schema/p"
		xmlns:util="http://www.springframework.org/schema/util" 
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:mvc="http://www.springframework.org/schema/mvc"
		xsi:schemaLocation="
			http://www.springframework.org/schema/beans
			http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/aop 
			http://www.springframework.org/schema/aop/spring-aop.xsd
			http://www.springframework.org/schema/tx 
			http://www.springframework.org/schema/tx/spring-tx.xsd
			http://www.springframework.org/schema/util 
			http://www.springframework.org/schema/util/spring-util.xsd
			http://www.springframework.org/schema/context
			http://www.springframework.org/schema/context/spring-context.xsd
			http://www.springframework.org/schema/mvc
			http://www.springframework.org/schema/mvc/spring-mvc.xsd">
		<bean id="hello" class="com.tarena.ioc.Hello"></bean>
		
		<bean id="msg" class="com.tarena.collection.Message">
			<property name="list">
				<list>
					<value>北京</value>
					<value>上海</value>
					<value>广州</value>
					<ref bean="hello"/>
				</list>
			</property>
			<property name="set">
				<set>
					<value>北京</value>
					<value>上海</value>
					<value>广州</value>
					<ref bean="hello"/>
				</set>
			</property>
			<property name="map">
				<map>
					<entry key="bj" value="北京"></entry>
					<entry key="sh" value="上海"></entry>
					<entry key="gz" value="广州"></entry>
					<entry key="h" value-ref="hello"></entry>
				</map>
			</property>
			<property name="props">
				<props>
					<prop key="bj">北京</prop>
					<prop key="sh">上海</prop>
					<prop key="gz">广州</prop>
				</props>
			</property>
		</bean>
	</beans>
  1. 间接集合注入: 特点:可以使用多次
   <?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:aop="http://www.springframework.org/schema/aop"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xmlns:p="http://www.springframework.org/schema/p"
		xmlns:util="http://www.springframework.org/schema/util" 
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:mvc="http://www.springframework.org/schema/mvc"
		xsi:schemaLocation="
			http://www.springframework.org/schema/beans
			http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/aop 
			http://www.springframework.org/schema/aop/spring-aop.xsd
			http://www.springframework.org/schema/tx 
			http://www.springframework.org/schema/tx/spring-tx.xsd
			http://www.springframework.org/schema/util 
			http://www.springframework.org/schema/util/spring-util.xsd
			http://www.springframework.org/schema/context
			http://www.springframework.org/schema/context/spring-context.xsd
			http://www.springframework.org/schema/mvc
			http://www.springframework.org/schema/mvc/spring-mvc.xsd">
		<bean id="hello" class="com.tarena.ioc.Hello"></bean>
		
		<!-- 间接集合注入 -->
		<util:list id="uList">
			<value>北京</value>
			<value>上海</value>
			<value>广州</value>
			<ref bean="hello"/>
		</util:list>
		<util:set id="uSet">
			<value>北京</value>
			<value>上海</value>
			<value>广州</value>
			<ref bean="hello"/>
		</util:set>
		<util:map id="uMap">
			<entry key="bj" value="北京"></entry>
			<entry key="sh" value="上海"></entry>
			<entry key="gz" value="广州"></entry>
			<entry key="h" value-ref="hello"></entry>
		</util:map>
		<util:properties id="uProps">
			<prop key="bj">北京</prop>
			<prop key="sh">上海</prop>
			<prop key="gz">广州</prop>
		</util:properties>
		<bean id="msg1" class="com.tarena.collection.Message">
			<property name="list" ref="uList"></property>
			<property name="set" ref="uSet"></property>
			<property name="map" ref="uMap"></property>
			<property name="props" ref="uProps"></property>
		</bean>	
	</beans>

表达式注入:

前提:必须有属性文件,表达式注入就是把属性文件的数据,通过spring注入给某个对象中表达式注入一定跟属性文件有关

	 mysql.properties
	 jdbc_driverClass=com.mysql.jdbc.Driver
	 jdbc_url=jdbc:mysql://localhost:3306/tesdb
	 jdbc_userName=root
	 jdbc_userPassword=root
	 public class JdbcUtil {
		private String driverClass;
		private String url;
		private String username;
		private String userpassword;
		public void setDriverClass(String driverClass) {
			this.driverClass = driverClass;
		}
		public void setUrl(String url) {
			this.url = url;
		}
		public void setUsername(String username) {
			this.username = username;
		}
		public void setUserpassword(String userpassword) {
			this.userpassword = userpassword;
		}
		@Override
		public String toString() {
			return "JdbcUtil [driverClass=" + driverClass + ", url=" + url + ", username=" + username + ", userpassword="
					+ userpassword + "]";
		}
		
	}

${}方式:

    <?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:aop="http://www.springframework.org/schema/aop"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xmlns:p="http://www.springframework.org/schema/p"
		xmlns:util="http://www.springframework.org/schema/util" 
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:mvc="http://www.springframework.org/schema/mvc"
		xsi:schemaLocation="
			http://www.springframework.org/schema/beans
			http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/aop 
			http://www.springframework.org/schema/aop/spring-aop.xsd
			http://www.springframework.org/schema/tx 
			http://www.springframework.org/schema/tx/spring-tx.xsd
			http://www.springframework.org/schema/util 
			http://www.springframework.org/schema/util/spring-util.xsd
			http://www.springframework.org/schema/context
			http://www.springframework.org/schema/context/spring-context.xsd
			http://www.springframework.org/schema/mvc
			http://www.springframework.org/schema/mvc/spring-mvc.xsd">
		<!-- 用spring加载指定的属性文件 ,多个文件用逗号间隔-->
		<context:property-placeholder location="classpath:conf/mysql.properties,classpath:conf/page.properties"/>
		<bean id="jdbcUtil" class="com.tarena.expression.JdbcUtil">
			<property name="driverClass" value="${jdbc_driverClass}"></property>
			<property name="url" value="${jdbc_url}"></property>
			<property name="username" value="${jdbc_userName}"></property>
			<property name="userpassword" value="${jdbc_userPassword}"></property>
		</bean>
		<bean id="pageUtil" class="com.tarena.expression.PageUtil">
			<property name="pageSize" value="${pageSize}"></property>
			<property name="showNum_a" value="${showNum_a}"></property>
		</bean>
	</beans>

#{}方式:

	<?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:aop="http://www.springframework.org/schema/aop"
		xmlns:tx="http://www.springframework.org/schema/tx"
		xmlns:p="http://www.springframework.org/schema/p"
		xmlns:util="http://www.springframework.org/schema/util" 
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:mvc="http://www.springframework.org/schema/mvc"
		xsi:schemaLocation="
			http://www.springframework.org/schema/beans
			http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/aop 
			http://www.springframework.org/schema/aop/spring-aop.xsd
			http://www.springframework.org/schema/tx 
			http://www.springframework.org/schema/tx/spring-tx.xsd
			http://www.springframework.org/schema/util 
			http://www.springframework.org/schema/util/spring-util.xsd
			http://www.springframework.org/schema/context
			http://www.springframework.org/schema/context/spring-context.xsd
			http://www.springframework.org/schema/mvc
			http://www.springframework.org/schema/mvc/spring-mvc.xsd">
		<!-- 用spring加载指定的属性文件 ,多个文件用逗号间隔-->
		<util:properties id="manyProperty"
			 location="classpath:conf/mysql.properties,classpath:conf/page.properties"></util:properties>
		
		<bean id="jdbcUtil" class="com.tarena.expression.JdbcUtil">
			<property name="driverClass" value="#{manyProperty.jdbc_driverClass}"></property>
			<property name="url" value="#{manyProperty.jdbc_url}"></property>
			<property name="username" value="#{manyProperty.jdbc_userName}"></property>
			<property name="userpassword" value="#{manyProperty.jdbc_userPassword}"></property>
		</bean>
		<bean id="pageUtil" class="com.tarena.expression.PageUtil">
			<property name="pageSize" value="#{manyProperty.pageSize}"></property>
			<property name="showNum_a" value="#{manyProperty.showNum_a}"></property>
		</bean>
	</beans>

空值注入:

	 public class Kong {
		private String str1;
		private String str2;
		public void setStr1(String str1) {
			this.str1 = str1;
		}
		public void setStr2(String str2) {
			this.str2 = str2;
		}
		@Override
		public String toString() {
			return "Kong [str1=" + str1 + ", str2=" + str2 + "]";
		}
		
	}
	<bean id="kong" class="com.tarena.kong.Kong">
		<property name="str1" value=""></property>
		<property name="str2">
			<null></null>
		</property>
	</bean>

构造函数注入数据

  1. 实例化对象
  2. 注入数据
	 public class ConstructorDI {
		private int age;
		private UserDao userDao;
		private String name;
		
		public ConstructorDI(int age,UserDao userDao,String name){
			this.age=age;
			this.userDao=userDao;
			this.name=name;
		}

		@Override
		public String toString() {
			return "ConstructorDI [age=" + age + ", userDao=" + userDao + ", name=" + name + "]";
		}
		
	}  
    <bean id="userDao" class="com.tarena.dao.impl.UserDaoImpl"></bean>
	<bean id="constructor" class="com.tarena.constructor.ConstructorDI">
		<constructor-arg index="0" value="18"></constructor-arg>
		<constructor-arg index="1" ref="userDao"></constructor-arg>
		<constructor-arg index="2" value="zhangsan"></constructor-arg>
	</bean>

对象注入和单值注入的另一种新写法

   <!-- 新写法 spring新的推荐写法
	如果没有ref   就是老写法的value
	有ref  就是引用容器的某个对象
	p:的值就是老写法的name
    -->
	<bean id="setterNew1" 
	      class="com.tarena.setternew.SetterNew"
	      p:name="张三"
	      p:age="18"
	      p:hello-ref="hello"
	      p:userDao-ref="userDao">
	</bean>

开发中用setter方式居多,构造函数注入方式少
在框架的源码中构造居多,setter方式也有

spring是如何处理继承:

spring中的继承需要注意问题:

  1. 对象都要交给spring实例化
  2. 对象的关系也要交给spring来管理
  3. 父类的对象是spring创建,而不是由原生java自动创建的
  4. 在子类对象中用parent属性指定spring容器中的父类对象
  5. 如果父类是抽象,要添加一个abstract=true
    <!-- 实例化DataSource对象 -->
	<bean id="dataSource" class="com.tarena.jicheng.DataSource">
		<property name="url" value="jdbc:mysql://localhost:3306/testdb"></property>
	</bean>
	<!-- 实例化BaseDao对象 -->
	<bean id="baseDao" 
	      class="com.tarena.jicheng.BaseDao"
	      abstract="true">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 实例化UserDao对象 -->
	<bean id="uDao"
	      class="com.tarena.jicheng.UserDao"
	      parent="baseDao">
	</bean>
public class DataSource {
		private String url;

		public String getUrl() {
			return url;
		}

		public void setUrl(String url) {
			this.url = url;
		}	
	}
	public abstract class BaseDao {
		private DataSource dataSource;

		public BaseDao(){
			System.out.println("BaseDao.constructor()");
		}
		public DataSource getDataSource() {
			return dataSource;
		}

		public void setDataSource(DataSource dataSource) {
			this.dataSource = dataSource;
		}
		
	}
	public class UserDao extends BaseDao {
		public UserDao(){
			System.out.println("UserDao.constructor()");
		}
		public int addUser(){
			System.out.println("addUser()");
			DataSource ds=super.getDataSource();
			System.out.println(ds.getUrl());
			return 0;
		}
	}
    @Test
	public void testMethod3(){
		//经过spring管理
		ApplicationContext context=
				new ClassPathXmlApplicationContext("spring_jicheng.xml");
		
		UserDao uDao=context.getBean("uDao",UserDao.class);
		uDao.addUser();		
	}

自动装配

在spring中能够提高开发效率那几种做法(不推荐:原因是降低代码的可读性) 所谓的spring的自动装配/自动注入

    <!-- spring中有关提高开发效率的做法 -->
	<!-- 
	autowire:自动装配
	autowire="byName" 按照名称装配
	
	首先反射com.tarena.wire.User类中的所有方法,
	找出所有的setter方法,把set去掉,把剩下的字符串的第一个字母小写
	拿剩下字符串作为id去spring容器中寻找对应的对象,如果找到就反射
	调用setter方法,注入对象 -->
	<bean id="user1" 
	      class="com.tarena.wire.User"
	      autowire="byName">
	</bean>
	<!-- 
	autowire:byType
	按类型装配,同样的类型在spring容器不能有第二个
	 -->
	<bean id="user2" 
	      class="com.tarena.wire.User"
	      autowire="byType">
	</bean>

注解

DI的注解

用spring中某些注解替换配置文件中的property节点

  • 用@Resource注解替换property节点 此注解是java的注解
  • 用@Autowired注解替换property节点 是spring框架的注解
  • 用@Inject注解替换property节点(不推荐使用)
  • 用@Value注解替换property节点(只能操作属性文件) 前提:
    需要注册一批java类来解析上面的注解
	 <context:annotation-config></context:annotation-config>

方式一: 用@Resource注解替换property节点

此注解是java的注解,隶属于javaEE规范

  1. 按照名称在spring容器中精确查找 name=”userDao” 拿userDao作为id去spring容器中寻找
public class UserServiceImpl{
	@Resource(name="userDao")
	private UserDao userDao;
}
  1. 按照属性名称userDao寻找 属性名称是userDao,拿userDao作为id去spring容器中寻找
    public class UserServiceImpl{
	    @Resource
		private UserDao userDao;
	}
  1. 按照类型UserDao寻找 按照userDao11这个id去spring容器寻找,如果没有就按照类型UserDao去寻找,如果有就注入(UserDao的类型不能有第二个),如果没有就无法注入,报异常
    public class UserServiceImpl{
	    @Resource
		private UserDao userDao11;
	}

总结:

  • 如果按照1方式就直接查找,找到注入,找不到报异常
  • 如果按照2方式就先按属性名称查找,找到注入
  • 找不到就按照3方式 按类型注入,找到注入 找不到报异常
    @Resource注解即可以写在属性上(用反射暴力注入)
    @Resource也可以写在方法上(用反射非暴力注入)

方式二: 用@Autowired注解替换property节点

@Autowired注解默认是按照类型注入/装配 1.默认按照类型装配/注入,在容器中不能第二个相同的类型 public class UserServiceImpl{ @Autowired private UserDao userDao; } public class UserServiceImpl{ //false:对象可以为null ,true:属性必须存储对象,不能为null @Autowired(required=false) private UserDao userDao; } 2.也可以按照名称注入/装配 @Autowired @Qualifier public class UserServiceImpl{ @Autowired @Qualifier(value=”userDao”) private UserDao userDao; }

方式四:用@Value注解替换property节点(只能操作属性文件)

mysql.properties

	 jdbc_driverClass=com.mysql.jdbc.Driver
	 jdbc_url=jdbc:mysql://localhost:3306/tesdb
	 jdbc_userName=root
	 jdbc_userPassword=root

1.@Value(“${属性的key}”)

    public class JdbcUtil1 {
		@Value("${jdbc_driverClass}")
		private String driverClass;
		@Value("${jdbc_url}")
		private String url;
		@Value("${jdbc_userName}")
		private String userName;
		@Value("${jdbc_userPassword}")
		private String userPassword;
		@Override
		public String toString() {
			return "JdbcUtil1 [driverClass=" + driverClass + ", url=" + url + ", userName=" + userName + ", userPassword="
					+ userPassword + "]";
		}	
	}

spring的清单文件:

    <!-- 用spring加载属性文件  多个文件用逗号间隔-->
    <context:property-placeholder location="classpath:conf/mysql.properties,classpath:conf/page.properties"/>
    <!-- 此节点注册了一批java类,这些java类用于解析下列注解
    	@Resource
    	@Autowired@Qualifer
        @Value
     -->
    <context:annotation-config></context:annotation-config>
	<bean id="jdbcUtil1" class="com.tarena.util.JdbcUtil1">
	</bean>

2.@Value(“#{id.属性的key}”)

		public class JdbcUtil2 {
		@Value("#{manyProperty.jdbc_driverClass}")
		private String driverClass;
		@Value("#{manyProperty.jdbc_url}")
		private String url;
		@Value("#{manyProperty.jdbc_userName}")
		private String userName;
		@Value("#{manyProperty.jdbc_userPassword}")
		private String userPassword;
		@Override
		public String toString() {
			return "JdbcUtil1 [driverClass=" + driverClass + ", url=" + url + ", userName=" + userName + ", userPassword="
					+ userPassword + "]";
		}
		
	}

spring的清单文件:

	<!-- 用spring加载属性文件  多个文件用逗号间隔-->
    <util:properties id="manyProperty"
      location="classpath:conf/mysql.properties,classpath:conf/page.properties"></util:properties>
    <!-- 此节点注册了一批java类,这些java类用于解析下列注解
    	@Resource
    	@Autowired@Qualifer
        @Value
     -->
    <context:annotation-config></context:annotation-config>
	<bean id="jdbcUtil2" class="com.tarena.util.JdbcUtil2">
	</bean>

IOC的注解

用spirng中某些注解替换配置文件中的bean节点

  • 用@Controller注解替换bean节点 应用控制器类上
  • 用@Service注解替换bean节点 应用在业务类上
  • 用@Repository注解替换bean节点 应用在dao类上
  • 用@Component注解替换bean节点 应用在无法归属类别的类上

以上注解用法基本相同,就以@Service注解为例:

  1. 上面的4个注解只能修饰在类上
  2. @Service 修饰在哪个类上,spring就实例化这个类的对象,并放在容器中管理,对象的名字,也是容器中对象的id的命名规则把类的名字第一个字母小写后的字符串做为id的值
  3. @Service(value=”名字”) 修饰在类上,value=是可以省略,spring实例化对象,并放在spring容器中,”名字”作为对象的id
  4. spring必须注册一批java类,用于解析上面的4个注解

注册注解的解析类

    <context:component-scan base-package="包名"></context:component-scan>

上下文的组件扫描 ,扫描的是包中的类
base-package属性指定的是包名,多个包名之间用逗号间隔
如果添加了这个组件扫描,就不需要添加

<context:annotation-config></context:annotation-config>

因为在注册组件扫描时,一并把

<context:annotation-config></context:annotation-config>

加载

补充几个常见的注解:

  1. @Scope(value=”prototype”) 多例 修饰在类上 @Scope(value=”singleton”) 单例 默认 修饰在类上
  2. @Lazy(value=true false) //懒加载 修饰在类上
  3. @PostConstruct //表示初始化 修饰在方法上
  4. @PreDestroy //表示销毁 修饰在方法上

Comments

Content