目录
1.spring简介
1.1 什么是spring?
- spring产生于2003年,轻量级javase/ee一站式(表示层、业务逻辑层、数据持久层)开源框架。
- ejb:javabean包含私有属性,公开的访问器,以及无参构造;
- spring的官网:http://spring.io/
1.2 spring在3层架构中的地位?
- 表示层:SpringMVC/struts2
- 业务逻辑层:Spring Framework,注意区分当前讲的spring是整个spring的体系结构包含Spring Framework。
- 数据持久层:Mybatis/Hibernate
1.3 spring的产生背景?点击查看spring产生的背景,创始人堪称大师级人物,学习的榜样
1.4 spring的优点?
- 方便解耦,简化开发:spring是工厂,负责创建对象以及对象关系维护。
- 支持aop编程(面向切面编程)
- sprint支持对优秀框架的集成(mybatis,struts2...)
- spring支持对javaee api的简化
- spring支持对junit的整合
1.5 spring的体系结构?
1.6 spring的核心?IOC和AOP
什么是Ioc?Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将对象创建和依赖的管理权限反转给spring容器。DI,即Dependency Injection,依赖注入。
什么是AOP?面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
2.spring入门案例
案例:
- UserService接口和UserServiceImpl实现类模拟业务逻辑层
- UserDao接口和UserDaoImpl实现类模拟数据持久化层
- 初步使用spring
步骤:
- 创建Java项目,导入jar包:4个核心jar包+commons-logging(日志增强,mybatis/lib目录下有)
- spring-beans-4.1.6.RELEASE.jar
- spring-context-4.1.6.RELEASE.jar
- spring-core-4.1.6.RELEASE.jar
- spring-expression-4.1.6.RELEASE.jar
- commons-logging-1.2.jar
- 编写接口+实现类
- 在src目录下创建并编写配置文件applicationContext.xml
- 获取配置信息并运行程序
代码:
接口及实现类
package dao;
public interface UserDao {
void addUser();
void deleteUser();
}
package dao.impl;
import dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
package service;
public interface UserService {
void addUser();
void deleteUser();
}
package service.impl;
import dao.UserDao;
import service.UserService;
public class UserServiceImpl implements UserService {
//接口引用+构造器
//接口引用+setter方法
private UserDao dao;
public void setDao(UserDao dao){
this.dao = dao;
}
public UserServiceImpl(UserDao dao){
this.dao = dao;
}
@Override
public void addUser() {
dao.addUser();
}
@Override
public void deleteUser() {
dao.deleteUser();
}
}
配置文件:applicationContext.xml
<?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:代表配置管理一个对象 id:唯一表示 class:类的完全限定名称-->
<bean id="userdao" class="dao.impl.UserDaoImpl"></bean>
<!-- 调用无参构造+setter方法创建对象 -->
<!-- <bean id="userservice" class="service.impl.UserServiceImpl">
给属性赋值 name:属性名称 value:赋值简单类型 ref:引用类型赋值,使用容器中以后的bean对象userdao
<property name="dao" ref="userdao"></property>
</bean> -->
<!-- 使用有参构造创建对象 -->
<bean id="userservice" class="service.impl.UserServiceImpl">
<!-- 构造参数:name:参数名称 value:简单类型赋值 ref:引用类型赋值 index:参数索引 type:参数类型-->
<!-- <constructor-arg name="dao" ref="userdao" index="" type=""></constructor-arg> -->
<constructor-arg index="0" ref="userdao" ></constructor-arg>
</bean>
</beans>
读取配置信息并运行程序
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;
public class Test {
public static void main(String[] args) {
//创建管理对象的权限都是开发者的
//spring容器先创建和管理dao对象(配置文件来实现)
//从spring容器中获取dao对象
/*ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao dao = ac.getBean("userdao",UserDao.class);
dao.addUser();
dao.deleteUser();*/
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userservice = ac.getBean("userservice", UserService.class);
userservice.addUser();
userservice.deleteUser();
}
}
3.bean的生命周期
bean生命周期图示(关键阶段用红框标记,下面逐个解释。)
BeanPostProcessors(Pre-initialization 和 Post-initialization):
- 有时希望咱Spring IoC容器初始化受管Bean前、属性设置后对该Bean先做一些预处理,或者在容器销毁受管Bean之前释放自己的资源。
- Spring IoC提供了多种方法来实现受管Bean的预处理和后处理。
- Spring中定义了BeanPostProcessors接口(如下方代码)。
- 若这个接口的某个实现类被注册到容器,那么该容器的每个受管Bean在调用初始化方法前,都会获得该接口实现类的一个回调。
- 容器调用接口定义的方法时会将该受管Bean的实例和名字通过参数传入方法,经过处理后通过方法的返回值返回给容器。
- 使用ApplicationContext容器会在配置文件自动寻找实现了BeanPostProcessor接口的bean,然后自动注册。
package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
Call custom init-method 和 Call custom destory-method:调用对象自定义初始化方法和自定义销毁方法。使用步骤如下:
- 在User类中定义init()和destory()方法
- 在applicationContext.xml配置文件中注册User,代码<bean id="user" class="pojo.User" init-method="init" destory-method="destory"></bean>
- 获取注册bean,则自动调用init()方法,关闭容器则自动调用destory()方法
- 关闭容器的代码:ac.getClasss().getMethod("close").invoke(ac);//ac就是ApplicationContext对象
Bean is Ready To Use / Container is Shutdown:表示对象以准备好可以使用 / 表示关闭spring容器
4.注解实现bean的装配
常用注解:
- @Component:创建对象,等价于<bean class=" "></bean>
- @Component("id"):创建对象,等价于<bean id=" " class=" "></bean>
- @Controller:用于表示层创建对象(主要是为了区分,其实都可以通用)
- @Service:用于业务逻辑层创建对象
- @Repository:用于数据持久层用于创建对象
- @Autowired:按照类型自动注入(找不到:不注入;找到1个:注入;找到多个:异常)
- 按照名称注入:
- @Autowird 和 @Qualifiler("name")
- @Resource(name="name")
使用步骤:
- 创建Java项目,导入jar包
- spring 4+1(5个包)
-
spring-aop.jar
- 分包:dao和dao.impl,service和service.impl
- 编写接口及实现类并注解实现类
- 编写applicationContext.xml配置文件:扫描注解并创建对象
- 读取配置并运行
示例代码:
dao和service包或子包中的代码
package dao;
public interface UserDao {
void addUser();
void deleteUser();
}
package dao.impl;
import org.springframework.stereotype.Repository;
import dao.UserDao;
//数据持久层创建对象的注解,userdao是所创建对象的名字
//创建对象需要:全限定类名+对象名(可选)
@Repository("userdao")
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
package service;
public interface Service {
void addUser();
void deleteUser();
}
package service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import dao.UserDao;
import service.Service;
//数据持久层创建对象的注解,service是所创建对象的名字
//这里Service注解名和Service接口名冲突了
//创建对象需要:全限定类名+对象名(可选)
@org.springframework.stereotype.Service("service")
public class ServiceImpl implements Service {
//按照类型自动注入,注入前提是spring Ioc容器中有该类型的对象
//找不到对象:则不注入;找到1个对象:则自动注入;找到多个对象:则报异常
@Autowired
private UserDao dao;
@Override
public void addUser() {
dao.addUser();
}
@Override
public void deleteUser() {
dao.deleteUser();
}
}
spring配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- 引入了context的命名空间,以及标签库 -->
<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">
<!-- 扫描指定包中的注解,才能创建对象并注入依赖,这里的包是基包,也就是说子包中的类也会被扫描 -->
<context:component-scan base-package="dao,service"></context:component-scan>
</beans>
Test测试类
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.Service;
public class Test {
public static void main(String[] args) {
//创建spring的ApplicationContext对象
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean对象:第一个参数指定Ioc容器中的对象名,第二个参数指定对象类型
Service service = application.getBean("service", Service.class);
service.addUser();
service.deleteUser();
}
}
5.spring整合junit
什么是junit?用于单元测试
如何使用junit?
- 导入jar包:Eclipse IDE自带,右键单击项目名称,选择build path,再选择add Libary,最后选择Junit即可
- 编写test()方法:在方法上方加上@Test注解,方法不能有返回值,不能有参数
- 运行test()方法:鼠标光标放置在方法名称,然后右键单击,选择run as,最后选择JUnit Test运行
常用Junit注解:
- @Test:注解方法,表示测试单元
- @Before:在单独执行单元前执行
- @After:在单独执行单元后执行
- 示例代码:
package test;
import org.junit.After;
import org.junit.Before;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.Service;
public class Test {
@Before
public void before(){
System.out.println("before");
}
@After
public void after(){
System.out.println("after");
}
@org.junit.Test
public void testService(){
//创建spring的ApplicationContext对象
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean对象:第一个参数指定Ioc容器中的对象名,第二个参数指定对象类型
Service service = application.getBean("service", Service.class);
service.addUser();
service.deleteUser();
}
}
断言Assert:
- 在运行之前推断代码的运行结果,如果推断正确,则正常运行;若推断错误,则运行失败。
- 示例代码:
package test;
import org.junit.Assert;
public class Test {
@org.junit.Test
public void test(){
Assert.assertEquals("aa","aa");
}
}
spring整合junit:
导入jar:spring-test.jar
示例代码:在前面注解注入代码的基础上修改如下
将test包加入扫描
<?xml version="1.0" encoding="UTF-8"?>
<!-- 引入了context的命名空间,以及标签库 -->
<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">
<!-- 扫描指定包中的注解,才能创建对象并注入依赖,这里的包是基包,也就是说子包中的类也会被扫描 -->
<context:component-scan base-package="dao,service,test"></context:component-scan>
</beans>
package test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import service.Service;
//设置执行器
@RunWith(SpringJUnit4ClassRunner.class)
//获取spring配置信息
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class Test {
//自动依赖注入
@Autowired
private Service service;
@org.junit.Test
public void test(){
service.addUser();
service.deleteUser();
}
}
6.代理
代理定义:对象访问前后实现预处理、过滤处理。比如在不改变原有增删改查代码的情况下,添加事务
代理分类:静态代理和动态代理
静态代理:
- 编译期间为每个委托类创建代理类
- 代理类与委托类实现同一个接口
- 示例代码:
//接口
package service;
public interface UserService {
void addUser();
void deleteUser();
}
package service.impl;
import service.UserService;
/**
* 委托类
*/
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
package service.proxy;
import service.UserService;
import service.impl.UserServiceImpl;
/**
* 代理类
* 注意:代理类和委托类实现同一个接口
*/
public class UserServiceProxy implements UserService {
UserService service = new UserServiceImpl();
@Override
public void addUser() {
System.out.println("开启事务");
service.addUser();
System.out.println("提交事务");
}
@Override
public void deleteUser() {
System.out.println("开启事务");
service.deleteUser();
System.out.println("提交事务");
}
}
package test;
import service.UserService;
import service.proxy.UserServiceProxy;
public class Test {
@org.junit.Test
public void testServiceProxy(){
UserService service = new UserServiceProxy();
service.addUser();
service.deleteUser();
}
}
动态代理:
- 运行期间为每个委托类的对象创建代理对象。两种方式,如下
- 接口+委托类(不需要实现类了),运行的时候直接创建代理对象
- 示例代码:
package service;
public interface UserService {
void addUser();
void deleteUser();
}
package service.impl;
import service.UserService;
/**
* 委托类
*/
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
package test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import service.UserService;
import service.impl.UserServiceImpl;
public class Test {
//无侵入式增强
@org.junit.Test
public void testServiceProxy(){
//1.创建委托类对象
UserService service = new UserServiceImpl();
//2.为委托类对象创建动态代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
service.getClass().getClassLoader(),
service.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("开启事务");
//手动调用方法
Object obj = method.invoke(service, args);
System.out.println("提交事务");
return obj;
}
});
//3.调用代理对象
proxy.addUser();
proxy.deleteUser();
}
}
7.aop
什么是aop?
- 面向切面编程;
- 采用横向抽取的方式,在运行阶段将增强代码织入目标对象的一种思想;
- 底层采用的是动态代理。
什么是横向抽取?http://www.bubuko.com/infodetail-2060817.html
aop应用场景有哪些?事务管理,日志系统,性能监测等。
aop框架有哪些?
- spring aop(spring-aop.jar)
- aspectj(aspecty.jar)
- jboss
aop的专业术语:
- target:目标对象。
- advice:通知,增强代码(遵循特定规范的增强代码)。
- joinpoint:连接点,即目标对象的方法。
- pointcut:切入点,真正添加增强代码的目标对象的方法。
- weaver:织入,增强代码添加到切入点的过程。
- aspect:切面,增强代码和切入点连接形成的逻辑面。
8.5 aop编程
配置方式实现:
- 创建Java项目并导入jar包:
- 4+1:前面项目的jar包
- spring-aop.jar:aop框架
- aspects.jar:aspectj规范
- aopalliance-1.0.jar:aop联盟(规范通知)
- aspectjweaver-1.8.5.jar:实现织入
- 编写目标类
- 编写增强类
- 编写applicationContext.xml配置文件
- 引人aop命名空间及其标签库
- 创建目标类对象
- 创建增强类对象
- 织入
- 配置切入点
- 配置切面:调用前增强和调用后增强
- 单元测试
- @ContextConfiguration("classpath:applicationContext.xml")
- @runtime(SpringJUnit4ClassRunner.class)
- @Autowired自动注入依赖
- 代码如下:
package service;
public interface UserService {
void addUser();
void deleteUser();
}
package service.impl;
import service.UserService;
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
package aspect;
public class MyAspect {
public void before(){
System.out.println("开启事务");
}
public void after(){
System.out.println("提交事务");
}
}
package test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import service.UserService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Main {
@Autowired
private UserService service;
@Test
public void test(){
service.addUser();
service.deleteUser();
}
}
applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 创建目标类对象 -->
<bean id="userservice" class="service.impl.UserServiceImpl"></bean>
<!-- 创建增强类对象 -->
<bean id="myaspect" class="aspect.MyAspect"></bean>
<!-- 织入 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* service..*(..))" id="mypoiontcut"/>
<!-- 配置切面 -->
<aop:aspect ref="myaspect">
<aop:before method="before" pointcut-ref="mypoiontcut"/>
<aop:after-returning method="after" pointcut-ref="mypoiontcut"/>
</aop:aspect>
</aop:config>
</beans>
注解方式实现:
- 创建Java项目并导入jar包:
- 4+1:前面项目的jar包
- spring-aop.jar:aop框架
- aspects.jar:aspectj规范
- aopalliance-1.0.jar:aop联盟(规范通知)
- aspectjweaver-1.8.5.jar:实现织入
- 编写目标类
- @Component("userservice")创建目标类对象
- 编写增强类
- @Component("myaspect")创建增强类对象
- @Aspect创建切面
- @PointCut("execution(* service..*(..))")创建切入点
- @Before("pointCut()")调用前增强
- @AfterReturning("pointCut()")调用后增强
- 编写applicationContext.xml配置文件
- 引入context命名空间及其标签库
- 引入aop命名空间及其标签库
- 扫描上下文注解并创建对象
- 声明自动代理
- 单元测试
- @ContextConfiguration("classpath:applicationContext.xml")
- @runtime(SpringJUnit4ClassRunner.class)
- @Autowired自动注入依赖
- 代码如下:
package service;
public interface UserService {
void addUser();
void deleteUser();
}
package service.impl;
import org.springframework.stereotype.Component;
import service.UserService;
@Component("userservice")
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
package aspect;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component("myaspect")
@Aspect
public class MyAspect {
@Pointcut("execution(* service..*(..))")
public void pointCut(){}
@Before("pointCut()")
public void before(){
System.out.println("开启事务");
}
@AfterReturning("pointCut()")
public void after(){
System.out.println("提交事务");
}
}
package test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import service.UserService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Main {
@Autowired
private UserService service;
@Test
public void test(){
service.addUser();
service.deleteUser();
}
}
applicationContext.xml
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="aspect,service"></context:component-scan>
<aop:aspectj-autoproxy/>
</beans>