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/EE full-stack(一站式) 轻量级开源框架
- spring 框架主要作用是和其他主流框架进行整合开发。SSM: spring springmvc mybatis
- Spring 是轻量级的框架,其基础版本只有 2 MB 左右的大小。
- spring在应用时需要加载服务较少。A --》B—》C
- spring有2个核心:1.IOC 2.AOP
Spring的优点: - 方便解耦,简化开发 (高内聚低耦合)
Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理
spring工厂是用于生成bean - AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能 - 声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程 - 方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序 - 方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持 - 降低JavaEE API的使用难度
Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
1. IOC(掌握)
IOC 全称 inversion of controll 控制反转
User类,创建User类对象,通过调用构造方法进行创建,User user = new User();
spring来管理对象的创建和销毁,把对象创建权利的反转称为控制反转。
User<---------spring(管理User—>创建User对象)
实例: 使用spring ioc来实现获取User对象
- 新建项目,java Project
- 添加所需要的依赖包
- 在项目的src目录下添加spring的配置文件
applicationContext.xml:
<!-- 配置User类 spring管理的类都用bean标签进行配置(spring管理的类也称为bean)
id:表示bean的唯一标识,每个bean的id值不能重复
name:表示bean的名称
class:表示bean所对应类的全限定名
-->
<bean id="user" name="user" class="com.xx.entity.User" ></bean>
- 在项目的src下新建User类
public class User {
Integer id;
String username;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public User() {
super();
}
}
5.测试:
public class TestIOC {
public static void main(String[] args) {
//1.创建ClassPathXmlApplicationContext对象//configLocation参数表示spring配置文件的位置
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取user对象
User user=context.getBean(User.class);
System.out.println(user);
}
}
以上为xml方式
下面以注解方式(不同之处)展示:
<!-- 配置注解扫描包 -->
<context:component-scan base-package="com.xx"/>
在 com,xx.entity中使用注解
/**
* @Component 组件,是spring提供得一个通用注解,用@Component注释的类会被spring进行实例化
* @Respository 作用和@Component一样,@Respository通常用在dao层
* @Service 作用和@Component一样,@Service 通常用在service层
* @Controller 作用和@Component一样,@Controller主要用在controlle类上
*
* @author Administrator
*
*/
依赖注入:dependency injection
spring不但可以负责类对象的创建,还可以建立(管理)bean与bean之间的依赖关系,
将spring管理bean与bean之间依赖的关系的过程称为 “依赖注入”
实例:建立userService 和userDAO之间的依赖关系?
xml方式:
- 1.setter方法注入
- 2.构造方法注入
- setter方法注入:
com.xx.service:
public class UserService {
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
public void save(){
System.out.println("UserSrvice_save...");
userDAO.save();
}
}
com.xx.test:
public class TestIOC {
public static void main(String[] args) {
//创建ClassPathXmlApplicationContext对象//configLocation参数表示spring配置文件的位置
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean(UserService.class);
userService.save();
}
}
配置:
<!-- 配置userDAO属性 property标签用来配置bean的属性
name属性的值和userService类中UserDAO的属性名一致
ref:表示当前属性引用的是哪个bean
-->
<!-- 配置UserDAO -->
<bean id="userDAO" name="userDAO" class="com.xx.dao.UserDAO" ></bean>
<!-- 配置UserService -->
<bean id="userService" name="userService" class="com.xx.service.UserService" >
<property name="userDAO" ref="userDAO"></property>
</bean>
输出:
UserSrvice_save…
userDAO_save…
- 构造方法注入:
com.xx.service:
public class UserService {
public UserService(UserDAO userDAO) {
super();
this.userDAO = userDAO;
}
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
public void save(){
System.out.println("UserSrvice_save...");
userDAO.save();
}
}
com.xx.test:
public class TestIOC {
public static void main(String[] args) {
//创建ClassPathXmlApplicationContext对象//configLocation参数表示spring配置文件的位置
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean(UserService.class);
userService.save();
}
}
配置:
<!-- 配置UserDAO -->
<bean id="userDAO" name="userDAO" class="com.xx.dao.UserDAO"></bean>
<!-- 配置UserService -->
<bean id="userService" name="userService" class="com.xx.service.UserService">
<!-- 配置bean构造方法参数 <constructor-arg>用来配置1个构造方法的参数
index表示构造方法参数的索引,从0开始
name表示构造方法参数的名称,名称与userService类构造方法参数的名称一致
-->
<constructor-arg name="userDAO" ref="userDAO"></constructor-arg>
</bean>
输出:
UserSrvice_save…
userDAO_save…
注解方式:
com.xx.service:
@Service
public class UserService {
//@Autowired注解可以将userService和userDAO建立关系,
//并且还会将userDAO进行实例化后,注入给userService
@Autowired
private UserDAO userDAO;
public void save(){
System.out.println("UserSrvice_save...");
userDAO.save();
}
}
com.xx.test:
public class TestIOC {
public static void main(String[] args) {
//创建ClassPathXmlApplicationContext对象//configLocation参数表示spring配置文件的位置
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean(UserService.class);
userService.save();
}
}
输出:
UserSrvice_save…
userDAO_save…
值注入:注入属性的值叫值注入
值注入方式:
- 1.setter方式注入
- 2.构造方法注入
- 3.p空间注入
1. setter方式注入
需求:User类:在创建对象的同时,赋值要已经赋初始值。
配置:
<!-- 配置UserDAO -->
<bean id="user" name="user" class="com.xx.entity.User" >
<property name="id" value="1000"></property>
<property name="username" value="admin"></property>
</bean>
com.xx.test:
public class TestIOC {
public static void main(String[] args) {
//1.创建ClassPathXmlApplicationContext对象//configLocation参数表示spring配置文件的位置
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取user对象
User user=context.getBean(User.class);
System.out.println(user.getId()+"---"+user.getUsername());
}
}
输出:
1000—admin
2. 构造方法注入
配置:
<bean id="user" name="user" class="com.xx.entity.User">
<constructor-arg name="id" value="1001"></constructor-arg>
<constructor-arg name="username" value="zhang3"></constructor-arg>
</bean>
com.xx.entity:
public User(Integer id, String username) {
super();
this.id = id;
this.username = username;
}
com.xx.test:
public class TestIOC {
public static void main(String[] args) {
//1.创建ClassPathXmlApplicationContext对象//configLocation参数表示spring配置文件的位置
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取user对象
User user=context.getBean(User.class);
System.out.println(user.getId()+"---"+user.getUsername());
}
}
输出:
1001—zhang3
3. p空间注入
在xml文件中添加p空间语法的支持
配置:
xmlns:p="http://www.springframework.org/schema/p"
<bean id="user" name="user" class="com.xx.entity.User" p:id="1002" p:username="li4">
com.xx.test:
public class TestIOC {
public static void main(String[] args) {
//1.创建ClassPathXmlApplicationContext对象//configLocation参数表示spring配置文件的位置
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取user对象
User user=context.getBean(User.class);
System.out.println(user.getId()+"---"+user.getUsername());
}
}
输出:
1002—li4
2. AOP(掌握)
- 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
- AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
- 经典应用:事务管理、性能监视、安全检查、缓存 、日志等
- Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
- AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
AOP实现原理:
- aop底层将采用代理机制进行实现
- 接口 + 实现类 :spring采用 jdk 的动态代理Proxy
- 实现类:spring 采用 cglib字节码增强
纵向抽取机制:
横向抽取机制:
关于AOP的几个术语:
需求: 在UserDAO的save方法执行之前或者添加日志功能:
采用2种方式:
- 1.xml文件方式
- 2.注解方式
前提:
导入jar包:aopalliance-1.0.jar,aspectjweaver.jar,spring-aspects-4.3.18.RELEASE.jar
1.xml文件方式
新建切面类,MyAspect:
com.xx.aspect
public class MyAspect {
//前置增强在目标方法执行执行先执行
public void before(){
System.out.println("before...");
}
//后置返回通知:正常情况下在目标方法执行之后执行
public void afterReturn(){
System.out.println("afterReturn...");
}
//异常通知:只有在异常情况下才会执行
public void afterThrowing(){
System.out.println("afterThrow...");
}
//最终通知:不管程序有没有异常,最终通知都会执行,正常情况下最终通知在后置返回通知之后执行
public void after(){
System.out.println("after...");
}
//环绕通知:在目标方法执行之前和之后都会执行
public void around(ProceedingJoinPoint proceedingJoinPoint){
try {
//前增强
System.out.println("prepare_do_method...");
//调用被增强类的方法
proceedingJoinPoint.proceed();
System.out.println("prepare_do_finish...");
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
com.xx.dao
@Repository
public class UserDAO {
public void save(){
//int i=1/0;
System.out.println("userDAO_save...");
}
}
配置:
<!-- 配置UserDAO -->
<bean id="userDAO" name="userDAO" class="com.xx.dao.UserDAO" ></bean>
<!-- 配置切面类 -->
<bean id="myAspect" class="com.xx.aspect.MyAspect"></bean>
<!-- 配置aop -->
<aop:config>
<!-- 配置切入点 expression表示切入点的表达式
取值语法: execution(方法返回值类型 包名.类名.方法名(..))
*:通配符
execution(* com.xx.dao.*.*(..))
id属性表示切入点的唯一标识
-->
<aop:pointcut expression="execution(* com.xx.dao.*.*(..))" id="pc"/>
<!-- 配置切面 ref表示切面类引用的bean -->
<aop:aspect id="as" ref="myAspect">
<!-- 配置增强
配置前置通知(增强) method属性表示切面类中增强方法的名称
pointcut-ref表示增强指向的切入点 -->
<aop:before method="before" pointcut-ref="pc"/>
<!-- 配置后置返回通知 -->
<aop:after-returning method="afterReturn" pointcut-ref="pc"/>
<!-- 配置异常通知:异常通知在发生异常的情况下才会执行 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pc"/>
<!-- 配置最终通知:不管程序有没有异常,最终通知都会执行 -->
<aop:after method="after" pointcut-ref="pc"/>
<!-- 配置环绕通知:在目标方法执行之前和之后都会执行 -->
<aop:around method="around" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
com.xx.test:
public class TestAOP {
public static void main(String[] args) {
//创建ClassPathApplicationContext对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取userDAO
UserDAO userDAO = context.getBean(UserDAO.class);
userDAO.save();
}
}
输出:
before…
prepare_do_method…
userDAO_save…
prepare_do_finish…
after…
afterReturn…
2.注解方式
com.xx.aspect
@Component
@Aspect
public class MyAspect {
//前置增强在目标方法执行执行先执行
//@Before注释前置通知 value属性用来指定切入点
@Before(value="execution(* com.xx.dao.*.*(..))")
public void before(){
System.out.println("before...");
}
//后置返回通知:正常情况下在目标方法执行之后执行
//@AfterReturing注释后置返回通知
@AfterReturning(value="execution(* com.xx.dao.*.*(..))")
public void afterReturn(){
System.out.println("afterReturn...");
}
//异常通知:只有在异常情况下才会执行
//@AfterThrwing用来注释异常通知
@AfterThrowing(value="execution(* com.xx.dao.*.*(..))")
public void afterThrowing(){
System.out.println("afterThrow...");
}
//最终通知:不管程序有没有异常,最终通知都会执行,正常情况下最终通知在后置返回通知之后执行
//@After注释最终通知
@After(value="execution(* com.xx.dao.*.*(..))")
public void after(){
System.out.println("after...");
}
//环绕通知:在目标方法执行之前和之后都会执行
//@Around用来注释环绕通知
@Around(value="execution(* com.xx.dao.*.*(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint){
try {
//前增强
System.out.println("prepare_do_method...");
//调用被增强类的方法
proceedingJoinPoint.proceed();
System.out.println("prepare_do_finish...");
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
com.xx.dao
@Repository
public class UserDAO {
public void save(){
//int i=1/0;
System.out.println("userDAO_save...");
}
}
配置:
<!-- 配置注解扫描包 -->
<context:component-scan base-package="com.xx"/>
<!-- 开启aop注解驱动 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
com.xx.test
public class TestAOP {
public static void main(String[] args) {
//创建ClassPathApplicationContext对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取userDAO
UserDAO userDAO = context.getBean(UserDAO.class);
userDAO.save();
}
}
输出:
prepare_do_method…
before…
userDAO_save…
prepare_do_finish…
after…
afterReturn…
注意:
xml方式和注解方式执行顺序不一样,正常情况和异常情况的执行顺序也不一致
注解方式下AOP执行顺序:
@Autowired和@Resource区别?
https://blog.csdn.net/bhdweb/article/details/84278918
参考: https://blog.csdn.net/qq_22583741/article/details/79589910#2-入门案例ioc