Spring
spring
①Spring是一个开源框架
③Spring是一个IOC(DI)和AOP容器框架。
④Spring的优良特性
[1]非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
[2]依赖注入:DI——Dependency Injection,反转控制(IOC)最经典的实现。
[3]面向切面编程:Aspect Oriented Programming——AOP
[4]容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期
[5]组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
[6]一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。
⑥Spring模块
1 安装Spring插件
①插件包:springsource-tool-suite-3.4.0.RELEASE-e4.3.1-updatesite.zip
②操作步骤:参照《参考资料:Spring插件安装图解.pptx》
2 搭建Spring运行时环境
①加入JAR包
[1]Spring自身JAR包:spring-framework-4.0.0.RELEASE\libs目录下
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
[2]commons-logging-1.1.1.jar
②根据需要创建Spring配置文件
/** * 细节:IOC容器中所有的组件默认是单例的; * 1、组件的创建对象是容器创建的; * 2、注册的组件,是在容器创建完全完成之前容器帮我们就创建好了; * 3、容器中创建的对象都是单例模式;多次获取都是获取之前创建好的对象; * 4、如果按照id获取,不存在,会抛出异常; * org.springframework.beans.factory. * NoSuchBeanDefinitionException: * No bean named 'person02' is defined * * 5、如果按照类型,这个类型的组件在容器中有多个,抛异常 * org.springframework.beans.factory. * NoUniqueBeanDefinitionException: * No qualifying bean of type [com.atguigu.bean.Person] * is defined: expected single matching bean but found 2: * person01,person02 * * 6、property是利用set方法赋值的,如果没有set方法也就坏了; * */ @Test public void test() { //1、实验1:通过IOC容器创建对象,并为属性赋值★ //1、从容器中获取刚才注册的组件; //1)、根据配置文件获取到容器对象 ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml"); System.out.println("容器创建完成....."); //2)、从容器中获取组件即可,按照组件的id获取 System.out.println("获取bean之前"); Person bean = (Person) ioc.getBean("person01"); System.out.println("获取bean之后"); Person bean2 = (Person) ioc.getBean("person01"); //3)、容器帮我们创建好了对象 System.out.println(bean == bean2); // Person bean3 = (Person) ioc.getBean("person02"); // System.out.println(bean3); //实验2:根据bean的类型从IOC容器中获取bean的实例★ Person person = ioc.getBean(Person.class); System.out.println("按照类型的:"+person); }
实验:
spring容器管理数据库连接池
<?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"> <!-- 引用外部属性文件 ioc容器中配置的所有组件,默认都是单实例 ,spring容器管理数据库连接池 c3p0-0.9.1.2.jar mysql-connector-java-5.1.7-bin.jar --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="root"></property> <property name="password" value="537423Ab"></property> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/bookstore"></property> </bean> </beans>
test
public class test { //将IOC容器本身实例化 ApplicationContext ioc = new ClassPathXmlApplicationContext("bean.xml"); @Test public void test() throws SQLException { //1、按照类型获取 //它会获得这个类型下的所有实现或者子类的对象 //ComboPooledDataSource是DataSource的实现 //确保只有一个DataSource配置在xml中 DataSource bean = ioc.getBean(DataSource.class); Connection connection = bean.getConnection(); System.out.println(connection); } }
/ComboPooledDataSource是DataSource的实现类
实验:配置外部属性文件*****
1.1 引用外部属性文件
当bean的配置信息逐渐增多时,查找和修改一些bean的配置信息就变得愈加困难。这时可以将一部分信息提取到bean配置文件的外部,以properties格式的属性文件保存起来,同时在bean的配置文件中引用properties属性文件中的内容,从而实现一部分属性值在发生变化时仅修改properties属性文件即可。这种技术多用于连接数据库的基本信息的配置。
①直接配置
<!-- 直接配置 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="root"/> <property name="password" value="root"/> <property name="jdbcUrl" value="jdbc:mysql:///test"/> <property name="driverClass" value="com.mysql.jdbc.Driver"/> </bean> |
②创建properties属性文件
prop.userName=root prop.password=root prop.url=jdbc:mysql:///test prop.driverClass=com.mysql.jdbc.Driver |
③引入context名称空间
④指定properties属性文件的位置
<!-- 指定properties属性文件的位置 --> <!-- classpath:xxx 表示属性文件位于类路径下 --> <context:property-placeholder location="classpath:jdbc.properties"/> |
⑤从properties属性文件中引入属性值
<!-- 从properties属性文件中引入属性值 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${prop.userName}"/> <property name="password" value="${prop.password}"/> <property name="jdbcUrl" value="${prop.url}"/> <property name="driverClass" value="${prop.driverClass}"/> </bean> |
/** * 实验18:使用@Autowired注解实现根据类型实现自动装配★ * 原理: * 1、先按照类型进行匹配:匹配上就赋值; * 按照类型找不到:(报错) * org.springframework.beans.factory.BeanCreationException: * Error creating bean with name 'bookServlet': * Injection of autowired dependencies failed; * Caused by: org.springframework.beans.factory. * NoSuchBeanDefinitionException: * No qualifying bean of type * [com.atguigu.service.BookService] * found for dependency: * expected at least 1 bean which qualifies as autowire candidate for this dependency. * * 2、如果按照类型找到多个:(如一个接口下有多个实现) * 1)、属性名作为id继续去ioc容器中查找找到既赋值; * 找id为bookService的对象; * 2)、找到就装配上 * 3)、找不到:报错 * org.springframework.beans.factory.BeanCreationException: * Caused by: org.springframework.beans.factory.BeanCreationException: * Could not autowire field: * private com.atguigu.service.BookService com.atguigu.servlet.BookServlet.bookServiceImpl001; * Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: * No qualifying bean of type [com.atguigu.service.BookService] is defined: * expected single matching bean but found 2: * bookService,bookServiceImpl * * * * 3、各种找不到情况; * * 使用@Autowired自动赋值 * 如果找到多个属性名会作为id继续查找;可以指定别用属性名做id了 * @Qualifier("bookServiceImpl")指定新的id作为去容器中查找的依据 * * @Autowired 的效果,一定要装配上。赋值不上就报错 * * 实验22:@Autowired注解的required属性指定某个属性允许不被设置 * @Autowired(required=false)能装上就装,不行就算了;
1 泛型依赖注入
1.1 简介
Spring 4.x中可以为子类注入子类对应的泛型类型的成员变量的引用。
1.2 实现
[1]组件基类
BaseRepository |
public class BaseRepository<T> {
public void save() { System.out.println("Saved by BaseRepository"); }
} |
BaseService |
public class BaseService<T> {
@Autowired private BaseRepository<T> repository;
public void add() { repository.save(); }
} |
[2]组件实体类
UserRepository |
@Repository public class UserRepository extends BaseRepository<User>{
public void save() { System.out.println("Saved by UserRepository"); }
} |
UserService |
@Service public class UserService extends BaseService<User>{
} |
[3]模型实体类
User |
public class User {
} |
[4]测试
ApplicationContext ioc = new ClassPathXmlApplicationContext("di.xml");
UserService us = (UserService) ioc.getBean("userService");
us.add(); |
执行结果 |
Saved by UserRepository |
1、BaseService没有在ioc容器;
但BaseService是UserService基类,BaseService的属性UserService可以共享
2、Autowired并没有在其他Service组件的属性中,怎么就注入成功了?(属性继承)
3、怎么知道UserRepository .add()?
根据泛型注入的类型属性映射到UserRepository。
给bean的属性赋值
1.1 集合属性
在Spring中可以通过一组内置的XML标签来配置集合属性,例如:<list>,<set>或<map>。
①数组和List
配置java.util.List类型的属性,需要指定<list>标签,在标签里包含一些元素:
1)、这些标签可以通过<value>指定简单的常量值;
<value> 历史</value >
2)、通过<ref>指定对其他Bean的引用;
<ref bean= "book01"/>
3)、通过<bean>指定内置bean定义;
<list> <!-- 每一个东西都是list里面的一个元素 --> <value>张三</value> <!-- 第二个元素是一个student01的对象, 引用其他bean、--> <ref bean="student01"/> <!-- 内部造 的一个bean对象,引用内部bean,外部拿不到,内部bean不写id --> <bean class="com.atguigu.bean.Student"> <property name="name" value="哈哈"></property> </bean>
</list>
4)通过<null/>指定空元素,甚至可以内嵌其他集合。
数组的定义和List一样,都使用<list>元素。
配置java.util.Set需要使用<set>标签,定义的方法与List一样。
<bean id="shop" class="com.atguigu.spring.bean.Shop" > <property name= "categoryList"> <!-- 以字面量为值的List集合 --> <list> <value> 历史</value > <value> 军事</value > </list> </property> <property name= "bookList"> <!-- 以bean的引用为值的List集合 --> <list> <ref bean= "book01"/> <ref bean= "book02"/> </list> </property> </bean >
②Map
Java.util.Map通过<map>标签定义,<map>标签里可以使用多个<entry>作为子标签。每个条目包含一个键和一个值。
必须在<key>标签里定义键。
因为键和值的类型没有限制,所以可以自由地为它们指定<value>、<ref>、<bean>或<null/>元素。
可以将Map的键和值作为<entry>的属性定义:简单常量使用key和value来定义;bean引用通过key-ref和value-ref属性定义。
<bean id="cup" class="com.atguigu.spring.bean.Cup"> <property name="bookMap"> <map> <entry> <key> <value>bookKey01</value> </key> <ref bean="book01"/> </entry> <entry> <key> <value>bookKey02</value> </key> <ref bean="book02"/> </entry> </map> </property> </bean>
③Properties
使用<props>定义java.util.Properties,该标签使用多个<prop>作为子标签。每个<prop>标签必须定义key属性
<bean class="com.atguigu.spring.bean.DataSource" id="dataSource"> <property name="properties"> <props> <prop key="userName">root</prop> <prop key="password">root</prop> <prop key="url">jdbc:mysql:///test</prop> <prop key="driverClass">com.mysql.jdbc.Driver</prop> </props> </property> </bean>
④集合类型的bean
如果只能将集合对象配置在某个bean内部,则这个集合的配置将不能重用。我们需要将集合bean的配置拿到外面,供其他bean引用。
配置集合类型的bean需要引入util名称空间
<util:list id="bookList"> <ref bean="book01"/> <ref bean="book02"/> <ref bean="book03"/> <ref bean="book04"/> <ref bean="book05"/> </util:list> <util:list id="categoryList"> <value>编程</value> <value>极客</value> <value>相声</value> <value>评书</value> </util:list>
使用级联属性赋值:
<bean id="book01" class="com.atguigu.bean.Book"> <property name="bookName" value="西游记"></property> <property name="price" value="98"></property> </bean> <bean id="student03" class="com.atguigu.bean.Student"> <property name="myBook" ref="book01"> <!-- <bean class="com.atguigu.bean.Book"> <property name="bookName" value="西游记"></property> </bean> --> </property> <!-- 级联属性,属性的属性。要小心。如果是引用会改掉外部的bean的值 --> <property name="myBook.bookName" value="东游记"></property> </bean>