概述
一、Spring简介
1.1 Spring是什么
Spring是分层的Java SE/EE应用full-stack轻量级开源框架,以IoC (Inverse Of Control:反转控制)和AOP (Aspect Oriented Programming:面向切面编程)为内核
提供了展现层SpringMVC 和持久层Spring JDBCTemplate以及业务层事务管理 等众多的企业开级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架
1.2 Spring发展历程
1997年,IBM提出了EJB的思想
1998年,SUN指定开发标准规范EJB1.0
1999年,EJB1.1发布
2001年,EJB2.0发布
2003年,EJB2.1发布
2006年,EJB3.0发布
Rod Johnson(Spring之父)
1.3 Spring的优势
方便解耦,简化开发
- 通过Spring提供的loC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。
AOP编程的支持
- 通过Spring的AOP功能,方便进行面向切面编程,许多不容易用传统OOP实现的功能可以通过AOP轻松实现。
声明式事务的支持
- 可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务管理,提高开发效率和质量。
方便程序的测试
- 可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事
方便集成各种优秀框架
- Spring对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的支持
降低JavaEE API的使用难度
- Spring对JavaEE API(如JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些API的使用难度大为降低
Java源码是经典学习典范
- Spring的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。它的源代码无意是Java技术的最佳实践的范例。
1.4 Spring的体系结构
二、Spring快速入门
2.1 Spring程序开发步骤
- 导入Spring开发的基本包坐标
- 编写Dao接口和实现类
- 创建Spring核心配置文件
- 在Spring配置文件中配置UserDaoImpl
- 使用Spring的API获得Bean实例
先导入Spring包
UserDao.java
public interface UserDao {
public void save();
}
UserDaoImpl.java
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save running...");
}
}
applicationContext.xml
<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.wangkai.dao.Impl.UserDaoImpl"></bean>
</beans>
测试UserDaoDemo.java
public class UserDaoDemo {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = app.getBean(UserDao.class);
userDao.save();
}
}
三、Spring配置文件
3.1 Bean标签基本配置
<bean id="userDao" class="com.wangkai.dao.Impl.UserDaoImpl">
用于配置对象交由Spring来创建
默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功
基本属性:
- id:Bean实例在Spring容器中的唯一标识
- class:Bean的全限定名称
3.2 Bean标签范围配置
scope:指对象的作用范围,取值如下:
取值范围 | 说明 |
---|---|
singleton | 默认值,单例的 |
prototype | 多例的 |
request | WEB项目中,Spring创建一个Bean的对象,将对象存放到request域中 |
session | WEB项目中,Spring创建一个Bean的对象,将对象存放到session域中 |
global session | WEB项目中,应用在Portlet环境中,如果没有Portlet环境那么globalSession相当于session |
singleton
<bean id="userDao" class="com.wangkai.dao.Impl.UserDaoImpl" scope="singleton"></bean>
@Test
//测试scope
public void test1(){
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao1 = app.getBean(UserDao.class);
UserDao userDao2 = app.getBean(UserDao.class);
System.out.println(userDao1); //com.wangkai.dao.Impl.UserDaoImpl@2353b3e6
System.out.println(userDao2); //com.wangkai.dao.Impl.UserDaoImpl@2353b3e6
//输出结果是一样的
//说明是单例的
}
prototype
<bean id="userDao" class="com.wangkai.dao.Impl.UserDaoImpl" scope="prototype"></bean>
@Test
//测试scope
public void test2(){
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao1 = app.getBean(UserDao.class);
UserDao userDao2 = app.getBean(UserDao.class);
System.out.println(userDao1); //com.wangkai.dao.Impl.UserDaoImpl@4d50efb8
System.out.println(userDao2); //com.wangkai.dao.Impl.UserDaoImpl@7e2d773b
//输出结果不一样
//说明是多例的
}
总结
当scope的取值为singleton时
- Bean的实例化个数:1个
- Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
- Bean的生命周期:
- 对象创建:当应用加载,创建容器时,对象就被创建了
- 对象运行:只要容器在,对象一直活着
- 对象销毁:当应用卸载,销毁容器时,对象就被销毁了
当scope的取值为prototype时
- Bean的实例化个数:多个
- Bean的实例化时机:当调用getBean()方法时实例化Bean
- Bean的生命周期:
- 对象创建:当使用对象时,创建新的对象实例
- 对象运行:只要对象在使用中,就一直活着
- 对象销毁:当对象长时间不用时,被Java的垃圾回收器回收了
3.3 Bean生命周期配置
- init-method:指定类中的初始化方法名称
- destroy-method:指定类中销毁方法名称
<bean id="userDao" class="com.wangkai.dao.Impl.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>
init-method=“init”
- 初始化完成时,执行
UserDaoImpl
中的init()
方法
destroy-method=“destroy”
- 销毁时,执行
UserDaoImpl
中的destroy()
方法
3.4 Bean实例化三种方式
无参构造方法实例化(重点)
- 前面讲的都是无参构造方法实例化
工厂静态方法实例化
静态工厂 StaticFactory.java
public class StaticFactory {
public static UserDao getUserDao(){
return new UserDaoImpl();
}
}
applicationContext.xml
<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.wangkai.factory.StaticFactory" factory-method="getUserDao"></bean>
</beans>
测试
@Test
public void test1(){
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao1 = app.getBean(UserDao.class);
System.out.println(userDao1);//可以输出到
app.close();
}
工厂实例方法实例化
工厂 DynamicFactory.java
public class DynamicFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
applicationContext.xml
<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">
<!-- 先创建DynamicFactory的对象 -->
<bean id="factory" class="com.wangkai.factory.DynamicFactory"/>
<!-- 再创建userDao -->
<bean id="userDao" factory-bean="factory" factory-method="getUserDao"/>
</beans>
测试
@Test
public void test1(){
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao1 = app.getBean(UserDao.class);
System.out.println(userDao1);//也是可以的
app.close();
}
3.5 Bean的依赖注入
因为UserService和UserDao都在Spring容器中,而最终程序直接使用的是UserService,所以可以在Spring容器中,将UserDao设置到UserService内部。
依赖注入(Dependency Injection):他是Spring框架核心IOC的具体实现
在编写程序时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。
IOC解耦只是降低他们的依赖关系,但不会消除。例如:业务层仍会调用持久层的方法
那这种业务层和持久层的依赖关系,在使用Spring之后,就让Spring来维护了
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去实现
Bean的依赖注入方式
怎么将UserDao注入到UserService内部呢?
构造方法
-
public class UserServiceImpl implements UserService { private UserDao userDao; public UserServiceImpl(UserDao userDao) { this.userDao = userDao; } public UserServiceImpl() { } @Override public void save() { userDao.save(); } }
-
<bean id="userDao" class="com.wangkai.dao.Impl.UserDaoImpl"/> <bean id="userService" class="com.wangkai.service.Impl.UserServiceImpl"> <constructor-arg name="userDao" ref="userDao"/> </bean>
set方法
-
public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao){ this.userDao = userDao; } @Override public void save() { userDao.save(); } }
-
<bean id="userDao" class="com.wangkai.dao.Impl.UserDaoImpl"/> <bean id="userService" class="com.wangkai.service.Impl.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean>
-
P命名空间注入本质也是set方法注入,但比起上述的set方法注入更加方便,主要体现在配置文件中,如下:
-
<!-- 首先要引入P命名空间 --> xmlns:p="http://www.springframework.org/schema/p" <!-- 其次,需要修改注入方式 --> <bean id="userDao" class="com.wangkai.dao.Impl.UserDaoImpl"/> <bean id="userService" class="com.wangkai.service.Impl.UserServiceImpl" p:userDao-ref="userDao">
Bean的依赖注入的数据类型
上面的操作,都是注入的引用Bean,除了对象的引用可以注入,普通数据类型,集合等都可以在容器中进行注入
注入数据的三种数据类型
-
普通数据类型
-
public class UserDaoImpl implements UserDao { private String username; private int age; public void setUsername(String username) { this.username = username; } public void setAge(int age) { this.age = age; } @Override public void save() { System.out.println(username+"====="+age); System.out.println("save running..."); } }
-
<bean id="userDao" class="com.wangkai.dao.Impl.UserDaoImpl"> <property name="username" value="zhangsan" /> <property name="age" value="18"/> </bean>
-
public class UserController { public static void main(String[] args) { ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) app.getBean("userService"); userService.save(); } /* 测试结果输出: zhangsan=====18 save running... */ }
-
-
引用数据类型
- 上一小节中
-
集合数据类型
-
public class UserDaoImpl implements UserDao { private List<String> strList; //自己创建一个User类 private Map<String, User> userMap; private Properties properties; public void setStrList(List<String> strList) { this.strList = strList; } public void setUserMap(Map<String, User> userMap) { this.userMap = userMap; } public void setProperties(Properties properties) { this.properties = properties; } @Override public void save() { System.out.println(strList); System.out.println(userMap); System.out.println(properties); System.out.println("save running..."); } }
-
<bean id="user1" class="com.wangkai.domain.User"> <property name="name" value="zhangsan"/> <property name="addr" value="济南"/> </bean> <bean id="user2" class="com.wangkai.domain.User"> <property name="name" value="lisi"/> <property name="addr" value="北京"/> </bean> <bean id="userDao" class="com.wangkai.dao.Impl.UserDaoImpl"> <property name="strList"> <list> <value>zhangsan</value> <value>lisi</value> <value>wangwu</value> </list> </property> <property name="userMap"> <map> <entry key="user1" value-ref="user1"/> <entry key="user2" value-ref="user2"/> </map> </property> <property name="properties"> <props> <prop key="p1">ppp1</prop> <prop key="p2">ppp2</prop> <prop key="p3">ppp3</prop> </props> </property> </bean>
-
public class UserController { public static void main(String[] args) { ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) app.getBean("userService"); userService.save(); } } /* [zhangsan, lisi, wangwu] {user1=User{name='zhangsan', addr='济南'},user2=User{name='lisi', addr='北京'}} {p3=ppp3, p2=ppp2, p1=ppp1} save running... */
-
3.6 引入其他配置文件(分模块开发)
实际开发中,Spring的配置文件内容非常多,这就导致Spring配置很繁杂且体积很大,所以将部分配置拆解到其他配置文件中,而在Spring主配置文件通过import标签进行加载
引入其他配置文件
<import resource="applicationContent-xxx.xml"/>
<import resource="applicationContent-user.xml"/>
3.7 知识要点
Spring的重点配置
<bean>标签
id属性:在容器中Bean实例的唯一标识,不允许重复
class属性:要实例化的Bean的全限定名
scope属性:Bean的作用范围
<property>标签:属性注入
name属性:属性名称
value属性:注入普通属性值
ref属性:注入的对象引用值
<list>标签
<map>标签
<properties>标签
<constructor-arg>标签
<import>标签:导入其他的Spring的分文件
四、Spring相关API
4.1 ApplicationContext的继承体系
applicationContext: 接口类型,代表应用上下文,可以通过其实例获得Spring容器中的Bean对象
- ClassPahtXmlApplicationContext
- 它是从类的根路径下加载配置文件推荐使用的
- FileSystemXmlApplicationContext
- 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
- AnnotationConfigApplicationContext
- 当使用竹节配置容器对象时,需要使用此类来创建spring容器。它用来读取注解
4.2 getBean()方法的使用
当参数的数据类型是字符串时,表示根据Bean的id从容器中获得Bean实例,返回值是Object,需要强转。当参数的数据类型是Class类型时,表示根据类型从容器中匹配Bean实例,当容器中相同类型的Bean有多个时,则此方法会报错
Object userService = app.getBean("userService");
UserService userService1 = app.getBean(UserService.class);
4.3 知识要点
Spring的重点API
ApplicationContext app = new ClassPathXmlApplicationContext("xml文件");
app.getBean("id");
app.getBean(Class);
五、Spring配置数据源(连接池)
5.1 数据源(连接池)的作用
-
数据源是提高程序性能而出现的
-
实现实例化数据源,初始化部分链接资源
-
使用连接资源时从数据源中获取
-
使用完毕后将连接资源归还给数据源
常见数据源:DBCP、C3P0、BoneCP、Druid等
5.2 数据源的开发步骤
- 导入数据源的坐标和数据库驱动坐标
- 创建数据源对象
- 设置数据源的基本连接数据
- 使用数据源获取连接资源和归还连接资源
jdbc.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=123456
test
@Test
public void test3() throws SQLException {
//读取配置文件
ResourceBundle jdbc = ResourceBundle.getBundle("jdbc");
String driver = jdbc.getString("driver");
String url = jdbc.getString("url");
String username = jdbc.getString("username");
String password = jdbc.getString("password");
//创建数据源对象
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
DruidPooledConnection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
5.3 Spring配置数据源
可以将DataSource的创建权交由Spring容器去完成
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
test
@Test
public void test4() throws SQLException {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
DruidDataSource dataSource = app.getBean(DruidDataSource.class);
DruidPooledConnection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
5.4 抽取jdbc配置文件
applicationContext.xml加载jdbc.properties配置文件获得连接信息
首先,需要引入context命名空间和入额数路径:
- 命名空间:
xmlns:context="http://www.springframework.org/schema/context"
- 约束路径:
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
jdbc.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
user=root
password=123456
applicationContext.xml
<!-- Spring容器加载properties -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</bean>
test
@Test
public void test4() throws SQLException {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
DruidDataSource dataSource = app.getBean(DruidDataSource.class);
DruidPooledConnection connection = dataSource.getConnection();
System.out.println(connection);
connection.close();
}
总结
<context:property-placeholder location="classpath:xx.properties"/>
<property name="" value="${key}"/>
六、Spring注解开发
6.1 Spring原始注解
Spring是请代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。
Spring原始注解主要替代<Bean>
的配置
注解 | 说明 |
---|---|
@Component | 使用在类上用于实例化Bean |
@Controller | 使用在web层类上用于实例化Bean |
@Service | 使用在service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用,用于根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Resource,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 注入Bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是Bean的销毁方法 |
注意: 使用注解进行开发时,需要在applicationContext.xml中配置组件扫描,作用是指定哪个包及其子包下的Bean需要进行扫描以便识别使用注解配置类、字段和方法
<context:component-scan base-package="com.wangkai"/>
简单使用
applicationContext.xml
<!-- 配置注解的组件扫描 -->
<context:component-scan base-package="com.wangkai"/>
UserDaoImpl.java
//<bean id="userDao" class="com.wangkai.dao.impl.UserDaoImpl"/>
@Component("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save run...");
}
}
UserServiceImpl.java
//<bean id="userService" class="com.wangkai.service.impl.UserServiceImpl"/>
@Component("userService")
public class UserServiceImpl implements UserService {
//<property name="userDao" ref="userDao"/>
@Autowired
@Qualifier("userDao")
private UserDao userDao;
@Override
public void save() {
userDao.save();
}
}
UserController.java
public class UserController {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = app.getBean(UserService.class);
userService.save();
}
}
详细学习
实例化Bean
@Component //使用在类上用于实例化Bean
@Controller //使用在web层类上用于实例化Bean
@Service //使用在service层类上用于实例化Bean
@Repository //使用在dao层类上用于实例化Bean
//下边三个和 @Component 的作用是一样的,只是作用在不同层上,方便阅读
注入引用类型的三个注解
//@Autowired //单独写这一个注解,会按照数据类型从Spring容器中进行匹配
//@Qualifier("userDao") //是按照id的名称从容器中进行匹配的,但是此处要结合上边一起用
@Resouce(name="userDao") //相当于@Autowired+@Resource
private UserDao userDao;
普通类型注入
@Value("Hello")
private String driver;
System.out.println(driver); //输出结果:Hello
对象的作用范围
@Scope("prototype") //多例的
@Scope("singleton") //单例的
public class UserDaoImpl implements UserDao {
初始化方法和销毁方法
@PostConstruct
public void init(){
System.out.println("初始化方法...");
}
@PreDestroy
public void destory(){
System.out.println("销毁方法...");
}
6.2 新注详解
注解 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个Spring配置类,当创建容器时会从该类上加载注解 |
@ComponentScan | 用于指定Spring在初始化容器是要扫描的包,作用和xml文件中的<context:component-scan base-package="com.wangkai"/> 一样 |
@Bean | 使用在方法上,标注将该方法的返回值存储到Spring容器中 |
@PropertySource | 用于加载.properties文件中的配置 |
@Import | 用于导入其他配置类 |
Spring配置类:SpringConfiguration.java
//标志该类是Spring的核心配置类
@Configuration
//<context:component-scan base-package="com.wangkai"/>
@ComponentScan("com.wangkai")
//<context:property-placeholder location="classpath:jdbc.properties"/>
@PropertySource("classpath:jdbc.properties")
public class SpringConfiguration {
@Value("${driver}")
private String driver;
@Value("${url}")
private String url;
@Value("${user}")
private String user;
@Value("${password}")
private String password;
@Bean("dataSource") //Spring会将当前方法的返回值以指定的名称存储到Spring容器中
public DataSource getDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(password);
return dataSource;
}
}
七、Spring整合Junit
- 方SpringJunit负责创建Spring容器,但是需要将配置文件的名称告诉它
- 将需要进行测试的Bean直接在测试类中进行注入
Spring集成Junit步骤
- 导入spring集成Junit的坐标
- 使用@Runwith注解替换原来的运行期
- 使用@ContextConfiguration指定配置文件或配置类
- 使用@Autowired注入需要测试的对象
- 创建测试方法进行测试
代码实现
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration("classpath:applicationContext.xml")
@ContextConfiguration(classes = {SpringConfiguration.class})
public class SpringJunitTest {
@Autowired
private UserService userService;
@Test
public void test1(){
userService.save();
}
}
最后
以上就是干净花瓣为你收集整理的Spring入门开发一、Spring简介二、Spring快速入门三、Spring配置文件四、Spring相关API五、Spring配置数据源(连接池)六、Spring注解开发七、Spring整合Junit的全部内容,希望文章能够帮你解决Spring入门开发一、Spring简介二、Spring快速入门三、Spring配置文件四、Spring相关API五、Spring配置数据源(连接池)六、Spring注解开发七、Spring整合Junit所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复