Spring 基本概述
1.1 Spring是什么
spring框架是于2003年兴起的一个轻量级的java开发框架,有Rod Johnson创建,是针对bean的生命周期进行管理的轻量级容器,使现有的技术更加容易使用,简单来说Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架 !
1.2 Spring的优点
1)方便解耦,简化开发
通过Spring提供的IOC容器,可以将对象间的依赖关系交友Spring进行控制,避免硬编码所造成的过度耦合。
2)AOP编程的支持
通过Spring的AOP功能,方便进行面向切面编程,许多不容易用传统OOP实现的功能可以通过AOP轻松实现。
3)声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务管理,提高开发效率和质量。
4)方便程序的测试
可以使用非容器依赖的编程方式进行几乎所有的测试工作,测试不在是昂贵的操做,而是随手可做的事情。
5)方便集成各种优秀框架
Spring对各种优秀框架(Struts,Hibernate,Hessian,Quartz等)的支持
6)降低javaaEE API的使用难度
Spring对javaEE API (如jdbc,javaMail,远程调用等) 进行了薄薄的封装,使这些API的使用难度大大降低
1.3 组成
什么是IOC
1. IOC本质
控制反转,是一种设计思想,DI(依赖注入) 是实现IOC的一种方法,通过描述(xml或者注解)并通过第三方去生产或获取特定对象的方法,在spring中实现控制反转的是IOC容器,其实现方法是依赖注入
2.xml方式开发
2.1 传统应用程序的队友是由程序本身控制创建,在哪里使用就在哪里new 对象
Users users = new Users(); //无参构造,通过set注入属性值
users.setUserId(1L);
users.setUserName("张三");
users.setUserPwd("123456");
Users users1 = new Users(1L,"张三","123456"); //全参构造
System.out.println(users.toString());// Users: userId=1,userName:张三,userPwd:123456;
System.out.println(users1.toString());// Users: userId=1,userName:张三,userPwd:123456;
2.2 Spring 创建bean
1)首先创建一个maven工程,在pom.xml文件中导入Spring的依赖
<!--测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<!--spring核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
2) 在resources包下创建applicationContext.xml配置文件,是Spring配置文件约定俗成的名字
3)在applicationContext.xml配置Users,这个时候bean没有被创建,当调用getBean()方法时才会实例化bean
4)bean的依赖注入,在applicationContext.xml通过构造函数,和set注入
数组,集合等数据类型,没写,请百度
<?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">
<!--这里就配置了Users的实例方法,等同于new Users(); -->
<bean id="users" class="cn.zb.spring.entity.Users" scope="singleton">
<!--默认使无参构造,下面使用有参构造,根据参数名,进行赋值-->
<!--<constructor-arg index="0" value="1"/> 根据参数下标进行赋值-->
<constructor-arg name="userId" value="1"/>
<constructor-arg name="userName" value="张三"/>
<constructor-arg name="userPwd" value="123"/>
<!--使用set注入属性值-->
<!--基本数据类型-->
<property name="userId" value="1"/>
</bean>
</beans>
spring提供IOC容器实现两种方式
BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供给开发任意使用
ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用
测试,通过applicationContext.xml配置文件获得User实例对象
ApplicationContext context=new ClassPathXmlApplicationContext("application.xml");
Users users = context.getBean("users", Users.class);
System.out.println(users.toString()); //Users: userId=1,userName:张三,userPwd:123;
5)bean的作用域
6)bean的自动装配
ByName:会自动在容器上下文中查找,和自己对象方法set对象后面的值对应的bean id,需要保证所有bean的id唯一
ByType:会自动在容器上下文中查找,和自己对象属性类型相同的bean,需要保证所有bean的class唯一
3.注解方式开发
3.1Spring原始注解
spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发时一种趋势,注解代替xml配置,提高开发效率
3.2 Spring新注解
使用新注解就是为了实现用注册代替原始注解不能表示的内容,全面替代之前的核心配置文件applicationContext.xml,使用核心配置类来进行配置,SpringConfiguration是核心配置类
package cn.zb.spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("cn.zb.spring")
public class SpringConfiguration {
}
UserService是接口,包含show()方法;
package cn.zb.spring.service.impl;
import cn.zb.spring.entity.Users;
import cn.zb.spring.service.UserService;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
//<bean id="userServiceImpl" class="cn.zb.spring.service.impl.UserServiceImpl">
//@Component("userServiceImpl")
//@Scope("singleton")
@Service
public class UserServiceImpl implements UserService {
@Override
public void show(Users users) {
System.out.println(users.toString());
}
@PostConstruct
@Override
public void init() {
System.out.println("初始化方法"); //在初始化以前执行
}
@PreDestroy
@Override
public void destroy() {
System.out.println("销毁方法"); //在容器销毁前执行,但是要改成手动关闭容器才行
}
}
3.3 Spring集成Junit测试
1)编写测试类
package cn.zb.test;
import cn.zb.spring.SpringConfiguration;
import cn.zb.spring.entity.Users;
import cn.zb.spring.service.UserService;
import cn.zb.spring.service.impl.UserServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class) //替换原来的运行期
@ContextConfiguration(classes = {SpringConfiguration.class}) //指定配置文件或配置类
public class SpringJunitTest {
@Autowired //注入对象
//@Qualifier("userServiceImpl")
//@Resource
private UserServiceImpl userService;
@Test
public void test(){
//Users users=new Users();
ApplicationContext context=new ClassPathXmlApplicationContext("application.xml");
Users users = context.getBean("users", Users.class);
userService.show(users); //Users: userId=1,userName:张三,userPwd:123;
}
}
什么是AOP
1.AOP简介
AOP 是面向切面 Aspect-oriented programming(方法)的编程的简写,AOP的实现可以把业务逻辑和系统级的服务进行隔离,是业务逻辑与各个系统级服务的耦合度降低,从而提高程序的重用性和开发效率,AOP的底层实现原理是动态代理。
下面的案例是基于JDK动态代理,JDK动态代理机制只能代理实现了接口的类
package cn.zb.spring.dao;
import cn.zb.spring.service.UserService;
import cn.zb.spring.service.impl.UserServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class UserDao {
private UserServiceImpl userServiceImpl=new UserServiceImpl();
/**
* getClassLoader() : 类加载器,用于加载代理类,使用真实对象的类加载器
* getInterfaces() : 真是对象所实习的接口,代理模式真实对象和代理对象实现相同的接口
* InvocationHandler() : 代理对象的调用处理程序
*/
public UserService getProxyObject(){
UserService userService=(UserService) Proxy.newProxyInstance(
userServiceImpl.getClass().getClassLoader(),
userServiceImpl.getClass().getInterfaces(),
new InvocationHandler() {
/**
* proxy : 代理对象
* method : 对应于在代理对象上调用的接口方法的Method实例
* args : 代理对象调用接口方法是传递的实际参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(userServiceImpl, args);
return result;
}
}
);
return userService;
}
}
@Test
public void test3(){
Users users = new Users(1L,"张三","123456");
UserDao userDao=new UserDao();
UserService proxyObject = userDao.getProxyObject();
proxyObject.show(users); //Users: userId=1,userName:张三,userPwd:123456;
}
2.什么是AspectJ
对于AOP的这种编程思想,由很多框架或者组件进行了实现,Spring实现AOP就是其中一种,AspectJ也实现了AOP而且实现方式更为简单,使用起来更为方便,所以Spring将AspectJ对于AOP的实现引入了自己的框架中。
2.1 AOP的几个术语
1)横切关注点
跨越应用程序多个模块的方法或功能,就是与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点,如日志,安全,缓存,事务等待
2)连接点
连接点是在应用执行中能够切入切面的一个点,即程序执行过程中能购应用通知的所有点
3)切点
切点是真正需要插入切面的一个或多个连接点,即通知被应用的具体位置,通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些点(比如Aspect切点表达式)
4)通知
切面的工作被成为通知。即包含了需要多个应用对象的横切行为
AspectJ的通知类型
@Before 前置通知
@Around 环绕通知
@AfterReturning 后置通知
@AfterThrowing 异常通知
@After 最终通知,不管是否异常,该通知都会执行
5)切面
切面式通知和切点的结合,通知和切点共同定义了切面的全部内容
6)织入
织入式把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接到被织入到目标对象中,在目标对象的生命周期里有多个点可以进行织入(编译期,类加载期,运行期)
7)引入
引入指定的是现有的类添加新方法或属性
2.2 Spring配置AspectJ
1)引入依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
2)使用xml方式配置
<bean id="userServiceImplProxy" class="cn.zb.spring.service.impl.UserServiceImplProxy"/>
<!--配置aop增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="p" expression="execution(* cn.zb.spring.service.impl.UserServiceImpl.show(..))"/>
<!--配置切面-->
<aop:aspect ref="userServiceImplProxy">
<!--增强方法作用在具体方法上-->
<aop:before method="beforeAdvice" pointcut-ref="p"/>
</aop:aspect>
</aop:config>
3)使用注解@Aspect创建切面
方法切入语法:
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
package cn.zb.spring.service.impl;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class UserServiceImplProxy {
//相同切入点提取
@Pointcut(value ="execution(* cn.zb.spring.service.impl.UserServiceImpl.show(..))")
public void executions(){};
@Before(value = "executions()")
public void beforeAdvice(){
System.out.println("前置通知");
}
@After(value = "executions()")
public void afterAdvice(){
System.out.println("最终通知");
}
@Around(value = "executions()")
public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕通知,在方法运行前执行");
pjp.proceed();
System.out.println("环绕通知,在方法运行后执行");
}
@AfterReturning(value = "executions()")
public void afterReturningAdvice(){
System.out.println("后置通知");
}
@AfterThrowing(value = "executions()")
public void afterThrowingAdvice(){
System.out.println("异常通知");
}
}
4)启用自动代理
在SpringConfiguration配置类添加注解@EnableAspectJAutoProxy
5)测试类运行,查看结果
本文做记录使用,参考了其他的文献
Spring集成数据库,mybatis在后面的Spring 教程(二)