目录
一、Spring简介
二、一个Demo带你使用Spring
三、浅尝Spring
1、hey,我们认识一下
2、我们加个微信吧
四、浅尝Spring而不止
1、我们恋爱吧
2、亲爱的,嫁给我
3、天大地大,老婆最大
一、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(一站式) 轻量级开源框架。
Spring有下面这么些个优点吧~
- 方便解耦,简化开发。Spring 就是一个大工厂,可以将所有对象创建和依赖关系维护,交给 Spring 管理
- AOP 编程的支持。Spring 提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能声明式事务的支持
- 只需要通过配置就可以完成对事务的管理,而无需手动编程方便程序的测试
- Spring 对 Junit4 支持,可以通过注解方便的测试 Spring 程序方便集成各种优秀框架
- Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz 等)的直接支持
- 降低 JavaEE API 的使用难度
- Spring 对 JavaEE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等),都提供了封装,使这些 API 应用难度大大降低
既然Spring这名流皮,我们为啥子不用呢?
二、一个Demo带你使用Spring
我们下载Spring的包之后,会发现有超级超级多的包,都不知道要用哪个好...辣肿么办楞?
才怪~这只是要使用Spring需要导入的最基础的包而已!你敢说你不用JDBC?你敢说不用Web?(΄ಢ◞౪◟ಢ‵)
导包之后,我们建一个简单的类,就叫User吧~我们随便设两个成员变量name和age,给出他们的get/set方法,重写toString方法。
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
接下来写配置,将对象注册到Spring容器。在src目录下建立名为applicationContext.xml的文件,引入约束文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd ">
<!-- 将User对象交给spring容器管理 -->
<!-- Bean元素:使用该元素描述需要spring容器管理的对象
class属性:被管理对象的完整类名.
name属性:给被管理的对象起个名字.获得对象时根据该名称获得对象.
可以重复.可以使用特殊字符.
id属性: 与name属性一模一样.
名称不可重复.不能使用特殊字符.
结论: 尽量使用name属性.
-->
<bean name="user" class="com.lbfl.domain.User" ></bean>
</beans>
接下来我们建立一个用于测试的类吧~
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.lbfl.domain.User;
public class Demo {
@Test
public void fun1(){
// 1 创建容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2 向容器"要"user对象
User u = (User) ac.getBean("user");
// 3 打印user对象
System.out.println(u);
}
}
我们右击fun1函数,使用JUnit运行它,会在控制台打印出User对象的相应信息。
三、浅尝Spring
1、hey,我们认识一下
想吃Spring,那先从IoC开始好了~
IOC:Inversion of Control 控制反转,指的是将对象的创建权反转(交给)给Spring,以实现了程序的解耦合 。
再简单提一下什么是DI——Dependency Injection依赖注入:需要有 IOC 的环境,Spring创建这个类的过程中,Spring 将类的依赖的属性设置进去。我们上面写的<bean></bean>就是在做这样的事情~
相信还记得我们刚才创建的applicationContext.xml文件的吧?在这个文件当中配置的bean们,每次容器启动时就会创建容器中配置的他们,并且能够提供更多功能,是Spring框架当中举足轻重的一部分!
2、我们加个微信吧
1.bean元素
关于bean元素的介绍,我们在前面的demo中已经说了很多了,这里就再补充辣么一点点~
对于bean元素,还有一个很重要的属性,scope属性,它的值可以是下面四个:singleton(默认值,单例模型,在Spring容器当中只会存在一个实例)、prototype(多例模型,在Spring容器当中可以有多个实例,每次调用都会创建一个新的实例)、request(web环境下,对象与request生命周期相同)、session(web环境下,对象与session生命周期相同)。
除此之外,bean元素还有init-method和destory-method两个属性,分别在对象创建和销毁后执行内部的方法,不做重点介绍。
2.对象创建
使用Spring创建对象,可以有多种方法,其中一种便是前面demo当中所使用的空参构造方式。
一种是静态工厂方法:即创建一个工厂类,在内部实现实例化的静态方法并返回实例对象,在applicationContext.xml文件当中进行配置~
import com.lbfl.domain.User;
public class UserFactory {
public static User createUser() {
System.out.println("静态工厂创建User");
return new User();
}
}
<!-- 创建方式2:静态工厂创建
调用UserFactory的createUser方法创建名为user2的对象.放入容器
-->
<bean name="user2"
class="com.lbfl.factory.UserFactory"
factory-method="createUser" ></bean>
还有一种是通过实例工厂创建:
import com.lbfl.domain.User;
public class UserFactory {
public User createUser() {
System.out.println("实例工厂创建User");
return new User();
}
}
<bean name="user3"
factory-bean="user"
factory-method="createUser" ></bean>
<bean name="user"
class="com.lbfl.factory.User" ></bean>
当然,后面两种方法仅需要了解即可,我们使用的最多的还是空参构造方法。
3.属性注入
我们主要讲set方法注入和构造函数注入这里两种方法,至于p名称空间注入和spEL方式注入就不做介绍了。
<!-- set方式注入: -->
<bean name="user" class="cn.itcast.bean.User" >
<!--值类型注入: 为User对象中名为name的属性注入tom作为值 -->
<property name="name" value="tom" ></property>
<property name="age" value="18" ></property>
<!-- 引用类型注入: 为car属性注入下方配置的car对象 -->
<property name="car" ref="car" ></property>
</bean>
<!-- 将car对象配置到容器中 -->
<bean name="car" class="cn.itcast.bean.Car" >
<property name="name" value="兰博基尼" ></property>
<property name="color" value="黄色" ></property>
</bean>
<!-- ============================================================ -->
<!-- 构造函数注入 -->
<bean name="user2" class="cn.itcast.bean.User" >
<!-- name属性: 构造函数的参数名 -->
<!-- index属性: 构造函数的参数索引 -->
<!-- type属性: 构造函数的参数类型-->
<constructor-arg name="name" index="0" type="java.lang.Integer" value="999" ></constructor-arg>
<constructor-arg name="car" ref="car" index="1" ></constructor-arg>
</bean>
四、浅尝Spring而不止
1、我们恋爱吧
都谈恋爱了,总让我打个标记是不是,不然别人怎么知道你是我的呢?
我们额外引入几个jar包,同时为我们的主配置文件applicationContext.xml文件引入新的命名空间:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd ">
接下来我们开启使用注解代理配置文件:
<!-- 指定扫描com.lbfl.domain包下的所有类中的注解.
注意:扫描包时.会扫描指定报下的所有子孙包
-->
<context:component-scan base-package="com.lbfl.domain"></context:component-scan>
将对象注册到容器,在User类中使用@Service、@Controller和@Repository注解,分别表示service层、web层和dao层的对象:
// user对应bean的名字
@Service("user")
public class User {
...
}
我们使用@Scope注解指定对象的作用范围(singleton表示单例,prototype表示多例):
@Scope(scopeName="prototype")
public class User {
...
}
当然,我们也可以使用@Value来为变量注入值:
public class User {
// 这里通过反射的域赋值,破坏了封装性,不推荐
@Value("tom")
private String name;
// 我们推荐使用set方法赋值
@Value("tom")
public void setName(String name) {
this.name = name;
}
}
我们使用@Autowire来表示自动装配,同时配合使用@Qualifier注解告诉Spring自动装配哪个名称的对象;或者我们可以使用@Resource注解来手动注入:
public class User {
// 自动装配名字为car1的bean
@Autowire
@Qualifier("car1")
private Car car1;
// 装配名为car2的bean
@Resource(name="car2")
private Car car2;
}
我们也可以使用@PostConstruct和@PreDestroy注解表示是在对象创建后和销毁前调用的方法~
2、亲爱的,嫁给我
从今往后,有我在,就没人能够伤害你!
横刀而立,为你挡住所有风雨,这,是——AOP
AOP思想就是把所有单个的以Servlet为例用到的公共方法抽取出来,比如,我们只要配置一个解决乱码的Filter让所有程序在运行前先通过它,那么我们就不用再每一个程序当中重复这个过程:
Spring中的AOP是为我们创建一个代理对象(所以要求我们的类不能使用final修饰符,因为类需要被继承~),进行统一管理:
如果被代理的对象有接口,那么Spring将优先使用动态代理技术;反之,Spring将使用第三方的cglib代理技术。
在AOP中有一些名词需要大家认识:
我们再使用一个demo来认识一下AOP吧~
首先我们需要再导入aspects包、aop包、aopalliance包和weaver包。
准备目标对象:
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("保存用户!");
//int i = 1/0;
}
@Override
public void delete() {
System.out.println("删除用户!");
}
@Override
public void update() {
System.out.println("更新用户!");
}
@Override
public void find() {
System.out.println("查找用户!");
}
}
准备通知方法:
import org.aspectj.lang.ProceedingJoinPoint;
//通知类
public class MyAdvice {
//前置通知
// |-目标方法运行之前调用
//后置通知(如果出现异常不会调用)
// |-在目标方法运行之后调用
//环绕通知
// |-在目标方法之前和之后都调用
//异常拦截通知
// |-如果出现异常,就会调用
//最终通知(无论是否出现 异常都会调用)
// |-在目标方法运行之后调用
//----------------------------------------------------------------
//前置通知
public void before(){
System.out.println("这是前置通知!!");
}
//后置通知
public void afterReturning(){
System.out.println("这是后置通知(如果出现异常不会调用)!!");
}
//环绕通知
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("这是环绕通知之前的部分!!");
Object proceed = pjp.proceed();//调用目标方法
System.out.println("这是环绕通知之后的部分!!");
return proceed;
}
//异常通知
public void afterException(){
System.out.println("出事啦!出现异常了!!");
}
//最终通知
public void after(){
System.out.println("这是最终通知(出现异常也会调用)!!");
}
}
配置applicationContext.xml文件,准备织入:
<!-- 准备工作: 导入aop(约束)命名空间 -->
<!-- 1.配置目标对象 -->
<bean name="userService" class="com.lbfl.service.impl.UserServiceImpl" ></bean>
<!-- 2.配置通知对象 -->
<bean name="myAdvice" class="com.lbfl.domain.MyAdvice" ></bean>
<!-- 3.配置将通知织入目标对象 -->
<aop:config>
<!-- 配置切入点
默认为public(可以不写),*不限返回方式,*ServiceImpl.*表示以ServiceImpl结尾的包下所有内容,(..)表示不限参数
public void com.lbfl.service.impl.UserServiceImpl.save()
void com.lbfl.service.impl.UserServiceImpll.save()
* com.lbfl.service.impl.UserServiceImpl.save()
* com.lbfl.service.impl.UserServiceImpl.*()
* com.lbfl.service.impl.*ServiceImpl.*(..)
-->
<aop:pointcut expression="execution(* com.lbfl.service.impl.*ServiceImpl.*(..))" id="pc"/>
<aop:aspect ref="myAdvice" >
<!-- 指定名为before方法作为前置通知 -->
<aop:before method="before" pointcut-ref="pc" />
<!-- 后置 -->
<aop:after-returning method="afterReturning" pointcut-ref="pc" />
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pc" />
<!-- 异常拦截通知 -->
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
<!-- 最终 -->
<aop:after method="after" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
3、天大地大,老婆最大
管着数据库呢,你说大不大?
准备db.properties文件,引入xml文件中:
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/spring
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=
配置applicationContext.xml文件:
<!-- 指定spring读取db.properties配置 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 1.将连接池放入spring容器 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="jdbcUrl" value="${jdbc.jdbcUrl}" ></property>
<property name="driverClass" value="${jdbc.driverClass}" ></property>
<property name="user" value="${jdbc.user}" ></property>
<property name="password" value="${jdbc.password}" ></property>
</bean>
<!-- 2.将JDBCTemplate放入spring容器 -->
<bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
<property name="dataSource" ref="dataSource" ></property>
</bean>
<!-- 3.将UserDao放入spring容器 -->
<bean name="userDao" class="com.lbfl.dao.impl.UserDaoImpl" >
<!-- <property name="jt" ref="jdbcTemplate" ></property> -->
<property name="dataSource" ref="dataSource" ></property>
</bean>
准备UserDaoImpl实现类(UserDao接口类就不给了,大家应该能看出来的):
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import com.lbfl.domain.User;
//使用JDBC模板实现增删改查
public class UserDaoImpl extends JdbcDaoSupport implements UserDao {
@Override
public void save(User u) {
String sql = "insert into t_user values(null,?) ";
super.getJdbcTemplate().update(sql, u.getName());
}
@Override
public void delete(Integer id) {
String sql = "delete from t_user where id = ? ";
super.getJdbcTemplate().update(sql,id);
}
@Override
public void update(User u) {
String sql = "update t_user set name = ? where id=? ";
super.getJdbcTemplate().update(sql, u.getName(),u.getId());
}
@Override
public User getById(Integer id) {
String sql = "select * from t_user where id = ? ";
return super.getJdbcTemplate().queryForObject(sql,new RowMapper<User>(){
@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {
User u = new User();
u.setId(rs.getInt("id"));
u.setName(rs.getString("name"));
return u;
}}, id);
}
@Override
public int getTotalCount() {
String sql = "select count(*) from t_user ";
Integer count = super.getJdbcTemplate().queryForObject(sql, Integer.class);
return count;
}
@Override
public List<User> getAll() {
String sql = "select * from t_user ";
List<User> list = super.getJdbcTemplate().query(sql, new RowMapper<User>(){
@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {
User u = new User();
u.setId(rs.getInt("id"));
u.setName(rs.getString("name"));
return u;
}});
return list;
}
}
引入测试类进行测试,大家可以对7个fun函数分别进行JUnit测试:
import java.beans.PropertyVetoException;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.lbfl.domain.User;
//演示JDBC模板
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo {
@Resource(name="userDao")
private UserDao ud;
@Test
public void fun1() throws Exception{
//0 准备连接池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///hibernate_32");
dataSource.setUser("root");
dataSource.setPassword("1234");
//1 创建JDBC模板对象
JdbcTemplate jt = new JdbcTemplate();
jt.setDataSource(dataSource);
//2 书写sql,并执行
String sql = "insert into t_user values(null,'rose') ";
jt.update(sql);
}
@Test
public void fun2() throws Exception{
User u = new User();
u.setName("tom");
ud.save(u);
}
@Test
public void fun3() throws Exception{
User u = new User();
u.setId(2);
u.setName("jack");
ud.update(u);
}
@Test
public void fun4() throws Exception{
ud.delete(2);
}
@Test
public void fun5() throws Exception{
System.out.println(ud.getTotalCount());
}
@Test
public void fun6() throws Exception{
System.out.println(ud.getById(1));
}
@Test
public void fun7() throws Exception{
System.out.println(ud.getAll());
}
}
我们今天所有的内容都在mysql的名为spring的数据库中进行的,hibernate会自动建表,但是数据库还是需要自己创建的!!!