Spring1
Spring技术是JavaEE开发必备技能,企业开发技术选型命中率>90%。
专业角度:
简化开发,降低企业级开发的复杂性。
框架整合,高效整合其他技术,提高企业级应用开发与运行效率。
Spring Framework系统架构
Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基。
代码书写现状:耦合度偏高
解决方案:使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象
IoC(Inversion of Control)控制反转:对象的创建控制权由程序转移到外部,这种思想称为控制反转
IoC(Inversion of Control)控制反转
使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
Spring技术对IoC思想进行了实现
Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的“外部”
IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean
DI(Dependency Injection)依赖注入
在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
目标:充分解耦
使用IoC容器管理bean(IoC)
在IoC容器内将有依赖关系的bean进行关系绑定(DI)
最终效果:使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系
1、在pom.xml中导入Spring坐标
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> </dependencies>
2、定义Spring管理的类(接口)
BookDao接口和BookDaoImpl实现类
1 public interface BookDao { 2 public void save(); 3 } 4 5 public class BookDaoImpl implements BookDao { 6 public void save() { 7 System.out.println("book dao save ..."); 8 } 9 }
BookService接口和BookServiceImpl实现类
1 public interface BookService { 2 public void save(); 3 } 4 5 public class BookServiceImpl implements BookService { 6 private BookDao bookDao = new BookDaoImpl(); 7 public void save() { 8 System.out.println("book service save ..."); 9 bookDao.save(); 10 } 11 }
3、创建Spring配置文件,配置对应类作为Spring管理的bean对象
在resources下定义applicationContext.xml配置文件并配置BookServiceImpl
<?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标签:表示配置bean id属性:表示给bean起名字 class属性:表示给bean定义类型 --> <bean id="bookService" class="com.test.service.impl.BookServiceImpl"></bean> </beans>
注:bean定义时id属性在同一个上下文中(IOC容器中)不能重复
4、初始化IOC容器(Spring核心容器/Spring容器),通过容器获取Bean对象
1 public class App { 2 public static void main(String[] args) { 3 //1.创建IoC容器对象,加载spring核心配置文件 4 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 5 //2 从IOC容器中获取Bean对象(BookService对象) 6 BookService bookService= (BookService)ctx.getBean("bookService"); 7 //3 调用Bean对象(BookService对象)的方法 8 bookService.save(); //book service save ... book dao save ... 9 } 10 }
DI入门案例
1、删除使用new的形式创建对象的代码
1 public class BookServiceImpl implements BookService { 2 private BookDao bookDao; //【第一步】删除使用new的形式创建对象的代码 3 public void save() { 4 System.out.println("book service save ..."); 5 bookDao.save(); 6 } 7 }
2、提供依赖对象对应的setter方法
1 public class BookServiceImpl implements BookService { 2 private BookDao bookDao; 3 public void save() { 4 System.out.println("book service save ..."); 5 bookDao.save(); 6 } 7 //【第二步】提供依赖对象对应的setter方法 8 public void setBookDao(BookDao bookDao) { 9 this.bookDao = bookDao; 10 } 11 }
3、配置service与dao之间的关系
在applicationContext.xml中配置
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 5 <!-- 6 bean标签:表示配置bean 7 id属性:表示给bean起名字 8 class属性:表示给bean定义类型 9 --> 10 <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/> 11 12 <bean id="bookService" class="com.test.service.impl.BookServiceImpl"> 13 <!--配置server与dao的关系 14 property标签:表示配置当前bean的属性 15 name属性:表示配置哪一个具体的属性 16 ref属性:表示参照哪一个bean 17 --> 18 <property name="bookDao" ref="bookDao"/> 19 </bean> 20 </beans>
bean
bean配置
bean基础配置(重点)
注:获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionException
NoSuchBeanDefinitionException: No bean named 'bookServiceImpl' available
扩展:scope的取值不仅仅只有singleton和prototype,还有request、session、application、 websocket ,表示创建出的对象放置在web容器(tomcat)对应的位置。比如:request表示保存到request域中。
注:在我们的实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。
bean实例化
bean本质上就是对象,创建bean使用构造方法完成
1 public class BookDaoImpl implements BookDao { 2 public BookDaoImpl() { 3 System.out.println("book dao constructor is running ...."); 4 } 5 public void save() { 6 System.out.println("book dao save ..."); 7 } 8 }
applicationContext.xml配置
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/>
无参构造方法如果不存在,将抛出异常BeanCreationException
实例化bean的三种方式——静态工厂(了解)
OrderDao接口和OrderDaoImpl实现类
1 public interface OrderDao { 2 public void save(); 3 } 4 public class OrderDaoImpl implements OrderDao { 5 public void save() { 6 System.out.println("order dao save ..."); 7 } 8 }
OrderDaoFatory工厂类
1 //静态工厂创建对象 2 public class OrderDaoFactory { 3 public static OrderDao getOrderDao(){ 4 System.out.println("factory setup...."); 5 return new OrderDaoImpl(); 6 } 7 }
applicationContext.xml配置
<bean id="orderDao" class="com.test.factory.OrderDaoFactory" factory-method="getOrderDao"/>
实例化bean的三种方式——实例工厂(了解)
UserDao接口和UserDaoImpl实现类
1 public interface UserDao { 2 public void save(); 3 } 4 public class UserDaoImpl implements UserDao { 5 public void save() { 6 System.out.println("user dao save ..."); 7 } 8 }
UserDaoFactory工厂类
1 //实例工厂创建对象 2 public class UserDaoFactory { 3 public UserDao getUserDao(){ 4 return new UserDaoImpl(); 5 } 6 }
applicationContext.xml配置
<bean id="userFactory" class="com.test.factory.UserDaoFactory"/> <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
实例化bean的第四种方式————
(定义UserDaoFactoryBean实现FactoryBean<UserDao>
UserDaoFactoryBean中实例化什么类型的对象泛型就是该类型。
1 //FactoryBean创建对象 2 public class UserDaoFactoryBean implements FactoryBean<UserDao> { 3 //代替原始实例工厂中创建对象的方法 4 public UserDao getObject() throws Exception { 5 return new UserDaoImpl(); 6 } 7 8 public Class<?> getObjectType() { 9 return UserDao.class; 10 } 11 }
applicationContext.xml配置
<bean id="userDao" class="com.test.factory.UserDaoFactoryBean"/>
生命周期:从创建到消亡的完整过程。
bean生命周期:bean从创建到销毁的整体过程。
bean生命周期控制:在bean创建后到销毁前做一些事情。
1 public class BookDaoImpl implements BookDao { 2 public void save() { 3 System.out.println("book dao save ..."); 4 } 5 //表示bean初始化对应的操作 6 public void init(){ 7 System.out.println("init..."); 8 } 9 //表示bean销毁前对应的操作 10 public void destory(){ 11 System.out.println("destory..."); 12 } 13 }
applicationContext.xml配置
<!--init-method:设置bean初始化生命周期回调函数,此处填写init方法名--> <!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象,此处填写destory方法名--> <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
测试类
1 public class AppForLifeCycle { 2 public static void main( String[] args ) { 3 //此处需要使用实现类类型,接口类型没有close方法 4 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 5 BookDao bookDao = (BookDao) ctx.getBean("bookDao"); 6 bookDao.save(); 7 //关闭容器,执行销毁的方法 8 ctx.close(); 9 } 10 }
2、实现InitializingBean, DisposableBean接口
1 public class BookServiceImpl implements BookService, InitializingBean, DisposableBean { 2 private BookDao bookDao; 3 public void setBookDao(BookDao bookDao) { 4 System.out.println("set ....."); 5 this.bookDao = bookDao; 6 } 7 public void save() { 8 System.out.println("book service save ..."); 9 bookDao.save(); 10 } 11 public void destroy() throws Exception { 12 System.out.println("service destroy"); 13 } 14 public void afterPropertiesSet() throws Exception { 15 System.out.println("service init"); 16 } 17 }
初始化容器
1.创建对象(内存分配)
2.执行构造方法
3.执行属性注入(set操作)
4.执行bean初始化方法
使用bean
1.执行业务操作
关闭/销毁容器
1.执行bean销毁方法
容器关闭前触发bean的销毁。
关闭容器方式:
手工关闭容器;
ConfigurableApplicationContext接口close()操作
注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机。
ConfigurableApplicationContext接口registerShutdownHook()操作
1 public class AppForLifeCycle { 2 public static void main( String[] args ) { 3 //此处需要使用实现类类型,接口类型没有close方法 4 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 5 6 BookDao bookDao = (BookDao) ctx.getBean("bookDao"); 7 bookDao.save(); 8 //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器 9 ctx.registerShutdownHook(); 10 //关闭容器 11 //ctx.close(); 12 } 13 }
依赖注入的两种方式:
1、setter注入
简单类型
引用类型(很常用)
2、构造器注入
简单类型
引用类型
1.1 setter注入——引用类型
在bean中定义引用类型属性并提供可访问的set方法
1 public class BookServiceImpl implements BookService{ 2 private BookDao bookDao; 3 public void setBookDao(BookDao bookDao) { 4 this.bookDao = bookDao; 5 } 6 }
配置中使用property标签ref属性注入引用类型对象
<bean id="bookService" class="com.test.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean> <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/>
1.2 setter注入——简单类型
在bean中定义简单类型属性并提供可访问的set方法
1 public class BookDaoImpl implements BookDao { 2 private int connectionNumber; 3 public void setConnectionNumber(int connectionNumber) { 4 this.connectionNumber = connectionNumber; 5 } 6 }
配置中使用property标签value属性注入简单类型数据
1 <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"> 2 <property name="connectionNumber" value="10"/> 3 </bean>
2.1 构造器注入——引用类型
在bean中定义引用类型属性并提供可访问的构造方法
1 public class BookServiceImpl implements BookService{ 2 private BookDao bookDao; 3 public BookServiceImpl(BookDao bookDao) { 4 this.bookDao = bookDao; 5 } 6 }
配置中使用constructor-arg标签ref属性注入引用类型对象
<bean id="bookService" class="com.test.service.impl.BookServiceImpl"> <constructor-arg name="bookDao" ref="bookDao"/> </bean> <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/>
2.2 构造器注入——简单类型
在bean中定义简单类型属性并提供可访问的构造方法
1 public class BookDaoImpl implements BookDao { 2 private int connectionNumber; 3 public void BookDaoImpl(int connectionNumber) { 4 this.connectionNumber = connectionNumber; 5 } 6 }
配置中使用constructor-arg标签value属性注入简单类型数据
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"> <constructor-arg name="connectionNumber" value="10"/> </bean>
2.3 构造器注入——参数适配(了解)
配置中使用constructor-arg标签type属性设置按形参类型注入
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"> <constructor-arg type="int" value="10"/> <constructor-arg type="java.lang.String" value="mysql"/> </bean>
配置中使用constructor-arg标签index属性设置按形参位置注入
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"> <constructor-arg index="0" value="10"/> <constructor-arg index="1" value="mysql"/> </bean>
依赖注入方式选择
1.强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
2.可选依赖使用setter注入进行,灵活性强
3.Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
4.如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
5.实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
6.自己开发的模块推荐使用setter注入
依赖自动装配(理解)
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
自动装配方式:
按类型(常用)
按名称
按构造方法
不启用自动装配
配置中使用bean标签autowire属性设置自动装配的类型
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.test.service.impl.BookServiceImpl" autowire="byType"/>
依赖自动装配特征:
1.自动装配用于引用类型依赖注入,不能对简单类型进行操作;
2.使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用;
3.使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用;
4.自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效。
集合注入
<property name="array"> <array> <value>100</value> <value>200</value> <value>300</value> </array> </property>
<property name="list"> <list> <value>itcast</value> <value>boxuegu</value> <value>chuanzhihui</value> </list> </property>
<property name="set"> <set> <value>itcast</value> <value>boxuegu</value> <value>boxuegu</value> </set> </property>
<property name="map"> <map> <entry key="country" value="china"/> <entry key="province" value="henan"/> <entry key="city" value="kaifeng"/> </map> </property>
<property name="properties"> <props> <prop key="country">china</prop> <prop key="province">henan</prop> <prop key="city">kaifeng</prop> </props> </property>
注:property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签。
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency>
配置DruidDataSource连接池Bean对象
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/spring_db"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean>
在测试类中从IOC容器中获取连接池对象并打印
1 public class App { 2 public static void main(String[] args) { 3 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 4 DataSource dataSource = (DataSource) ctx.getBean("dataSource"); 5 System.out.println(dataSource); 6 } 7 }
<dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency>
配置c3p0连接池Bean对象
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/> <property name="user" value="root"/> <property name="password" value="root"/> <property name="maxPoolSize" value="1000"/> </bean>
在测试类中从IOC容器中获取连接池对象并打印
1 public class App { 2 public static void main(String[] args) { 3 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 4 DataSource dataSource = (DataSource) ctx.getBean("dataSource"); 5 System.out.println(dataSource); 6 } 7 }
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
在applicationContext.xml中开启context命名空间,加载jdbc.properties属性文件
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> </beans>
使用context命名空间,加载指定properties文件
<context:property-placeholder location="jdbc.properties"/>
在配置连接池Bean的地方使用EL表达式获取jdbc.properties属性文件中的值
<bean class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean>
如果属性文件中配置的不是jdbc.username,而是username=root666,那么使用${username}获取到的不是root666,而是计算机的名称。
原因:系统属性的优先级比我们属性文件中的高,替换了我们的username=root666。
解决:
解决1:换一个名称,例如不叫username,叫jdbc.username。
解决2:使用system-properties-mode="NEVER"属性表示不使用系统属性。
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
加载多个properties文件
<context:property-placeholder location="jdbc.properties,msg.properties"/>
加载所有properties文件
<context:property-placeholder location="*.properties"/>
<context:property-placeholder location="classpath:*.properties"/>
从类路径或jar包中搜索并加载properties文件
<context:property-placeholder location="classpath*:*.properties"/>
方式一:类路径加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
方式二:文件路径加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\applicationContext.xml");
加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml", "bean2.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
方式二:使用bean名称获取并指定类型(推荐使用)
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
方式三:使用bean类型获取(如果IOC容器中同类型的Bean对象有多个,此处获取会报错)
BookDao bookDao = ctx.getBean(BookDao.class);
1 Resource resources = new ClassPathResource("applicationContext.xml"); 2 BeanFactory bf = new XmlBeanFactory(resources); 3 BookDao bookDao = bf.getBean("bookDao", BookDao.class); 4 bookDao.save();
BeanFactory创建完毕后,所有的Bean均为延迟加载,也就是说我们调用getBean()方法获取Bean对象时才创建Bean对象并返回给我们。
ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载。
核心容器总结
bean相关
依赖注入相关
基本使用
1、在applicationContext.xml中开启Spring注解包扫描
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:context="http://www.springframework.org/schema/context" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation=" 6 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 8 <!--扫描com.test包及其子包下的类中注解--> 9 <context:component-scan base-package="com.test"/> 10 </beans>
2、在类上使用@Component注解定义Bean
1 @Component("bookDao") 2 public class BookDaoImpl implements BookDao { 3 public void save() { 4 System.out.println("book dao save ..."); 5 } 6 } 7 @Component 8 public class BookServiceImpl implements BookService { 9 private BookDao bookDao; 10 public void setBookDao(BookDao bookDao) { 11 this.bookDao = bookDao; 12 } 13 public void save() { 14 System.out.println("book service save ..."); 15 bookDao.save(); 16 } 17 }
补充说明:如果@Component注解没有使用参数指定Bean的名称,那么类名首字母小写就是Bean在IOC容器中的默认名称。例如:BookServiceImpl对象在IOC容器中的名称是bookServiceImpl。
3、在测试类中获取Bean对象
1 public class AppForAnnotation { 2 public static void main(String[] args) { 3 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 4 BookDao bookDao = (BookDao) ctx.getBean("bookDao"); 5 System.out.println(bookDao); 6 //按类型获取bean 7 BookService bookService = ctx.getBean(BookService.class); 8 System.out.println(bookService); 9 } 10 }
Spring提供@Component注解的三个衍生注解:
@Controller:用于表现层bean定义
@Service:用于业务层bean定义
@Repository:用于数据层bean定义
1 @Repository("bookDao") 2 public class BookDaoImpl implements BookDao { 3 } 4 5 @Service 6 public class BookServiceImpl implements BookService { 7 }
Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道。
Java类代替Spring核心配置文件:
@Configuration注解用于设定当前类为配置类
@ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
@ComponentScan({com.test.service","com.test.dao"})
读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象
1 //加载配置文件初始化容器 2 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 3 //加载配置类初始化容器 4 ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
1 @Repository 2 @Scope("singleton") 3 public class BookDaoImpl implements BookDao { 4 }
1 @Repository 2 @Scope("singleton") 3 public class BookDaoImpl implements BookDao { 4 public BookDaoImpl() { 5 System.out.println("book dao constructor ..."); 6 } 7 @PostConstruct 8 public void init(){ 9 System.out.println("book init ..."); 10 } 11 @PreDestroy 12 public void destroy(){ 13 System.out.println("book destory ..."); 14 } 15 }
注:@PostConstruct和@PreDestroy注解是jdk中提供的注解,从jdk9开始,jdk中的javax.annotation包被移除了,也就是说这两个注解就用不了了,可以额外导入一下依赖解决这个问题。
<dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency>
注解开发依赖注入(重点)
1 @Service 2 public class BookServiceImpl implements BookService { 3 //@Autowired:注入引用类型,自动装配模式,默认按类型装配 4 @Autowired 5 private BookDao bookDao; 6 }
说明:不管是使用配置文件还是配置类,都必须进行对应的Spring注解包扫描才可以使用。@Autowired默认按照类型自动装配,如果IOC容器中同类的Bean有多个,那么默认按照变量名和Bean的名称匹配,建议使用@Qualifier注解指定要装配的bean名称
注:
自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法。
自动装配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法。
1 @Service 2 public class BookServiceImpl implements BookService { 3 //@Autowired:注入引用类型,自动装配模式,默认按类型装配 4 @Autowired 5 //@Qualifier:自动装配bean时按bean名称装配 6 @Qualifier("bookDao") 7 private BookDao bookDao; 8 }
注:@Qualifier注解无法单独使用,必须配合@Autowired注解使用
1 @Repository("bookDao") 2 public class BookDaoImpl implements BookDao { 3 @Value("100") 4 private String connectionNum; 5 }
加载properties文件
jdbc.properties属性文件:
name=spring
使用@PropertySource注解加载properties文件:
1 @Configuration 2 @ComponentScan("com.test") 3 //@PropertySource加载properties配置文件 4 @PropertySource({"classpath:jdbc.properties"}) //单文件{}可以省略不写;多文件使用{} 5 public class SpringConfig { 6 }
注:@PropertySource()中加载多文件请使用数组格式配置,不允许使用通配符*
@Value注解中使用${name}从属性文件中读取name值:
1 @Repository("bookDao") 2 public class BookDaoImpl implements BookDao { 3 //@Value:注入简单类型(无需提供set方法) 4 @Value("${name}") 5 private String name; 6 7 public void save() { 8 System.out.println("book dao save ..." + name); 9 } 10 }
注解开发管理第三方Bean(重点)
第三方bean管理
使用@Bean配置第三方bean
1 @Configuration 2 public class SpringConfig { 3 //@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中 4 @Bean 5 public DataSource dataSource(){ 6 DruidDataSource ds = new DruidDataSource(); 7 ds.setDriverClassName("com.mysql.jdbc.Driver"); 8 ds.setUrl("jdbc:mysql://localhost:3306/spring_db"); 9 ds.setUsername("root"); 10 ds.setPassword("root"); 11 return ds; 12 } 13 }
使用独立的配置类管理第三方bean
方式一:导入式
1 public class JdbcConfig { 2 @Bean 3 public DataSource dataSource(){ 4 DruidDataSource ds = new DruidDataSource(); 5 ds.setDriverClassName("com.mysql.jdbc.Driver"); 6 ds.setUrl("jdbc:mysql://localhost:3306/spring_db"); 7 ds.setUsername("root"); 8 ds.setPassword("root"); 9 return ds; 10 } 11 }
使用@Import注解手动加入配置类到核心配置,此注解只能添加一次,多个数据请用数组格式
1 @Configuration 2 //@Import:导入配置信息 3 @Import({JdbcConfig.class}) 4 public class SpringConfig { 5 }
方式二:扫描式(不推荐,在SpringConfig和JdbcConfig等中有多个@Configuration配置类)
1 @Configuration 2 public class JdbcConfig { 3 @Bean 4 public DataSource dataSource(){ 5 DruidDataSource ds = new DruidDataSource(); 6 ds.setDriverClassName("com.mysql.jdbc.Driver"); 7 ds.setUrl("jdbc:mysql://localhost:3306/spring_db"); 8 ds.setUsername("root"); 9 ds.setPassword("root"); 10 return ds; 11 } 12 }
使用@ComponentScan注解扫描配置类所在的包,加载对应的配置类信息
1 @Configuration 2 @ComponentScan({"com.test.config","com.test.service","com.test.dao"}) //只要com.test.config包扫到了就行,三个包可以合并写成com.test 3 public class SpringConfig { 4 }
第三方bean依赖注入(重点)
简单类型依赖注入
1 public class JdbcConfig { 2 //1.定义一个方法获得要管理的对象 3 @Value("com.mysql.jdbc.Driver") 4 private String driver; 5 @Value("jdbc:mysql://localhost:3306/spring_db") 6 private String url; 7 @Value("root") 8 private String userName; 9 @Value("root") 10 private String password; 11 //2.@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中 12 @Bean 13 public DataSource dataSource(){ 14 DruidDataSource ds = new DruidDataSource(); 15 ds.setDriverClassName(driver); 16 ds.setUrl(url); 17 ds.setUsername(userName); 18 ds.setPassword(password); 19 return ds; 20 } 21 }
说明:如果@Value()中使用了EL表达式读取properties属性文件中的内容,那么就需要加载properties属性文件。
引用类型依赖注入
1 //Spring会自动从IOC容器中找到BookDao对象赋值给参数bookDao变量,如果没有就会报错。 2 @Bean 3 public DataSource dataSource(BookDao bookDao){ 4 System.out.println(bookDao); 5 DruidDataSource ds = new DruidDataSource(); 6 ds.setDriverClassName(driver); 7 ds.setUrl(url); 8 ds.setUsername(userName); 9 ds.setPassword(password); 10 return ds; 11 }
说明:引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象
XML配置与注解配置比较
1. 在pom.xml中添加spring-context、druid、mybatis、mysql-connector-java等基础依赖。
2. 准备service和dao层基础代码:
1 public interface AccountService { 2 void save(Account account); 3 void delete(Integer id); 4 void update(Account account); 5 List<Account> findAll(); 6 Account findById(Integer id); 7 } 8 @Service 9 public class AccountServiceImpl implements AccountService { 10 11 @Autowired 12 private AccountDao accountDao; 13 14 public void save(Account account) { 15 accountDao.save(account); 16 } 17 public void update(Account account){ 18 accountDao.update(account); 19 } 20 public void delete(Integer id) { 21 accountDao.delete(id); 22 } 23 public Account findById(Integer id) { 24 return accountDao.findById(id); 25 } 26 public List<Account> findAll() { 27 return accountDao.findAll(); 28 } 29 } 30 public interface AccountDao { 31 @Insert("insert into tbl_account(name,money)values(#{name},#{money})") 32 void save(Account account); 33 34 @Delete("delete from tbl_account where id = #{id} ") 35 void delete(Integer id); 36 37 @Update("update tbl_account set name = #{name} , money = #{money} where id = #{id} ") 38 void update(Account account); 39 40 @Select("select * from tbl_account") 41 List<Account> findAll(); 42 43 @Select("select * from tbl_account where id = #{id} ") 44 Account findById(Integer id); 45 }
【第一步】在pom.xml中导入Spring整合Mybatis依赖
1 <dependency> 2 <groupId>org.springframework</groupId> 3 <artifactId>spring-jdbc</artifactId> 4 <version>5.2.10.RELEASE</version> 5 </dependency> 6 <dependency> 7 <groupId>org.mybatis</groupId> 8 <artifactId>mybatis-spring</artifactId> 9 <version>1.3.0</version> 10 </dependency>
【第二步】创建JdbcConfig配置DataSource数据源
1 jdbc.driver=com.mysql.jdbc.Driver 2 jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false 3 jdbc.username=root 4 jdbc.password=root
1 public class JdbcConfig { 2 @Value("${jdbc.driver}") 3 private String driver; 4 @Value("${jdbc.url}") 5 private String url; 6 @Value("${jdbc.username}") 7 private String userName; 8 @Value("${jdbc.password}") 9 private String password; 10 11 @Bean 12 public DataSource dataSource(){ 13 DruidDataSource ds = new DruidDataSource(); 14 ds.setDriverClassName(driver); 15 ds.setUrl(url); 16 ds.setUsername(userName); 17 ds.setPassword(password); 18 return ds; 19 } 20 }
【第三步】创建MybatisConfig整合mybatis
1 public class MybatisConfig { 2 //定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象 3 @Bean 4 public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){ 5 SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); 6 ssfb.setTypeAliasesPackage("com.test.domain"); 7 ssfb.setDataSource(dataSource); 8 return ssfb; 9 } 10 //定义bean,返回MapperScannerConfigurer对象 11 @Bean 12 public MapperScannerConfigurer mapperScannerConfigurer(){ 13 MapperScannerConfigurer msc = new MapperScannerConfigurer(); 14 msc.setBasePackage("com.test.dao"); 15 return msc; 16 } 17 }
使用SqlSessionFactoryBean封装SqlSessionFactory需要的环境信息
使用MapperScannerConfigurer加载Dao接口,创建代理对象保存到IOC容器中
1 @Configuration 2 @ComponentScan("com.test") 3 //@PropertySource:加载类路径jdbc.properties文件 4 @PropertySource("classpath:jdbc.properties") 5 @Import({JdbcConfig.class,MybatisConfig.class}) 6 public class SpringConfig { 7 }
1 public class App { 2 public static void main(String[] args) { 3 ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); 4 AccountService accountService = ctx.getBean(AccountService.class); 5 Account ac = accountService.findById(1); 6 System.out.println(ac); 7 } 8 }
Spring整合Junit单元测试【重点】
1 <!--junit--> 2 <dependency> 3 <groupId>junit</groupId> 4 <artifactId>junit</artifactId> 5 <version>4.12</version> 6 </dependency> 7 <!--spring整合junit--> 8 <dependency> 9 <groupId>org.springframework</groupId> 10 <artifactId>spring-test</artifactId> 11 <version>5.1.9.RELEASE</version> 12 </dependency>
1 //【第二步】使用Spring整合Junit专用的类加载器 2 @RunWith(SpringJUnit4ClassRunner.class) 3 //【第三步】加载配置文件或者配置类 4 @ContextConfiguration(classes = {SpringConfig.class}) //加载配置类 5 //@ContextConfiguration(locations={"classpath:applicationContext.xml"})//加载配置文件 6 public class AccountServiceTest { 7 //支持自动装配注入bean 8 @Autowired 9 private AccountService accountService; 10 @Test 11 public void testFindById(){ 12 System.out.println(accountService.findById(1)); 13 } 14 @Test 15 public void testFindAll(){ 16 System.out.println(accountService.findAll()); 17 } 18 }
注:junit的依赖至少要是4.12版本,可以是4.13等版本,否则出现如下异常: