顶级架构师学习——第二十阶段:Spring春天来了

25 篇文章 2 订阅
4 篇文章 0 订阅

春天来了,想的倒好~(。ŏ_ŏ)

没有春天,Spring要不要——要也不给!

这个感觉...难道是真的!!!

目录

一、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有下面这么些个优点吧~

  1. 方便解耦,简化开发。Spring 就是一个大工厂,可以将所有对象创建和依赖关系维护,交给 Spring 管理
  2. AOP 编程的支持。Spring 提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能声明式事务的支持
  3. 只需要通过配置就可以完成对事务的管理,而无需手动编程方便程序的测试
  4. Spring 对 Junit4 支持,可以通过注解方便的测试 Spring 程序方便集成各种优秀框架
  5. Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz 等)的直接支持
  6. 降低 JavaEE API 的使用难度
  7. 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会自动建表,但是数据库还是需要自己创建的!!!


啊~睡醒了,原来tm还是单身,打扰了...

我是小昶,明天见呐~

欢迎关注我们的公众号:落饼枫林,一起交流学习(´⊙ω⊙`)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值