史上最全讲解:Spring详解
Spring第一天
高级课程安排
阶段一
SSM框架(Spring SpringMVC MyBatis)
FreeMaker模板引擎
EasyUI框架
CRM项目(后台管理项目)
阶段二
商城项目
Dobbu分布式
Redis缓存
RabbitMQ消息队列
Spring Boot框架
Spring Cloud微服务
Spring框架
Spring框架是一个开源的JavaEE应用程序
主要核心是Ioc(控制反转/依赖注入) 与Aop(面向切面)两大技术
Spring IOC
Spring AOP
Spring JDBC+事务
Spring作用
Dao层
JDBC处理(BaseDao)
对应的框架:MyBatis
Service层
Spring框架不是针对Service层业务逻辑 没有适合的框架
Web层(Controller层)
Servlet(接收参数 响应数据 地址配置 页面转发)
对应的框架:SpringMVC
Spring基于分布式的应用程序
基于轻量级的框架
配置管理
Bean对象的实例化-IOC
集成其他的第三方技术
MyBatis、Hibernate框架(持久层框架)
SpringMVC
Spring Security权限
Quartz时钟框架(定时任务处理)
自带的服务
Mail 邮件处理
定时任务处理-定时调度(定时短信、定时任务)
消息处理(异步处理)
Spring模块划分
Spring IOC模块:Bean对象的实例化 Bean的创建
Spring AOP模块:动态代理 面向切面编程
Spring JDBC+事务模块
Spring Web模块
Spring的环境搭建
1、新建Maven项目
选择"File" —> 选择"New" —> 选择Maven
2、设置项目的坐标
3、设置项目的Maven环境
4、设置项目的名称和存放的工作空间
5、修改项目中pom.xml的配置
5.1 修改JDK版本
<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties>
5.2 修改单元测试的版本
<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies>
5.3 删除build标签中的pluginManagement标签
<!--删除build标签中的pluginManagement标签--><build></build>
5.4 添加Spring的依赖坐标
Maven仓库:https://mvnrepository.com/
<!--添加Spring的依赖坐标-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.3.9.RELEASE</version>
</dependency>
6、添加Spring的配置文件 spring.xml
6.1 在项目的src下创建文件夹(Alt+insert)
6.2 将文件夹标注为资源目录
6.3 新建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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="..." class="..."><!-- collaborators and configuration for this bean go here --></bean><bean id="..." class="..."><!-- collaborators and configuration for this bean go here --></bean><!-- more bean definitions go here --></beans>
7、创建Bean对象
8、通过Spring.xml配置Bean对象
<bean id="userService" class="com.shsxt.service.UserService"></bean>
9、加载配置文件,获取实例化对象
public static void main(String[] args) {// 获取Spring上下文环境ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");// 通过getBean方法得到Spring容器中实例化好的Bean对象UserService userService = (UserService) ac.getBean("userService");// 调用方法userService.test();}
Spring IOC 核心技术
工厂设计模式 (简单工厂 工厂方法 抽象工厂) (大话设计模式.pdf C#)
XML解析 (Dom4J)
反射(实例化对象 反射获取方法 反射获取属性 反射获取构造器 反射方法调用 )
策略模式(加载资源)
单例(IOC创建的实例化对象都是单例)
Spring IOC 配置文件的加载方式
根据相对路径加载资源
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
根据绝对路径加载资源(了解)
ApplicationContext ac = new FileSystemXmlApplicationContext("F:\\SHSXT\\Java\\33\\idea_workspace\\spring01\\src\\main\\resources\\spring.xml");
同时加载多个资源文件
1. 可变参数,传入多个文件名
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml","dao.xml");
2. 通过总的配置文件import其他配置文件
service.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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!--导入需要包含的资源文件--><import resource="spring2.xml"/><import resource="dao.xml"/></beans>
spring2.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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!--xmlns 即 xml namespace xml使用的命名空间xmlns:xsi 即xml schema instance xml 遵守的具体规范xsi:schemaLocation 本文档xml遵守的规范 官方指定--><!--Bean标签:Bean对象的实例化id 唯一标识(bean对象) 值不可重复class 类的全路径 包名.类名--><bean id="userService" class="com.shsxt.service.UserService"> </bean></beans>
dao.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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userDao" class="com.shsxt.dao.UserDao"></bean>
</beans>
加载时只需加载总的配置文件即可
// 加载总的资源文件
ApplicationContext ac = new ClassPathXmlApplicationContext("service.xml");
Spring IOC 对象实例化的三种方式
构造器实例化
注:通过默认构造器创建 空构造方法必须存在 否则创建失败
ApplicationContext ac = new ClassPathXmlApplicationContext("spring2.xml");
UserService userService = (UserService) ac.getBean("userService");
userService.test();
<bean id="userService" class="com.shsxt.service.UserService"> </bean>
静态工厂实例化(了解)
<!--静态工厂-->
<bean id="userController" class="com.shsxt.factory.StaticFactory" factory-method="createUserService"></bean>
实例化工厂实例化(了解)
<!--实例化工厂-->
<bean id="intanceFactory" class="com.shsxt.factory.IntanceFactory"></bean>
<bean id="userController" factory-bean="intanceFactory" factory-method="crateUser"></bean>
Spring三种实例化bean的方式比较
方式一:通过bean的缺省构造函数创建,当各个bean的业务逻辑相互比较独立的时候或者和外界关联较少的时候可以使用。
方式二:利用静态factory方法创建,可以统一管理各个bean的创建,如各个bean在创建之前需要相同的初始化处理,则可用这个factory方法险进行统一的处理等等。
方式三:利用实例化factory方法创建,即将factory方法也作为了业务bean来控制,
1可用于集成其他框架的bean创建管理方法,2能够使bean和factory的角色互换。
Spring第二天
Spring IOC注入(DI)
Spring IOC 手动装配(注入)
set(方法)注入 推荐使用
1、属性字段提供set方法
public class UserService {// 业务对象UserDao set注入(提供set方法)private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}// 业务对象StudentDao set注入(提供set方法)private StudentDao studentDao;public void setStudentDao(StudentDao studentDao) {this.studentDao = studentDao;}// 常用对象String set注入(提供set方法)private String host;public void setHost(String host) {this.host = host;}// 基本类型Integer set注入(提供set方法)private Integer port;public void setPort(Integer port) {this.port = port;}// List集合 set注入(提供set方法)public List<String> list;public void setList(List<String> list) {this.list = list;}// List集合输出public void printList() {list.forEach(s -> System.out.println(s));}// Set集合 set注入(提供set方法)private Set<String> set;public void setSet(Set<String> set) {this.set = set;}// Set集合输出public void printSet() {set.forEach(s -> System.out.println(s));}// Map set注入(提供set方法)private Map<String,Object> map;public void setMap(Map<String, Object> map) {this.map = map;}// Map输出public void printMap() {map.forEach((k,v) -> System.out.println(k + "," + v));}// Properties set注入(提供set方法)private Properties properties;public void setProperties(Properties properties) {this.properties = properties;}// Properties输出public void printProperties(){properties.forEach((k,v) -> System.out.println(k + ","+ v ));}public void test(){System.out.println("UserService Test...");userDao.test();studentDao.test();System.out.println("Host:" + host + ",port:" + port);// List集合printList();// Set集合printSet();// MapprintMap();// PropertiesprintProperties();}
}
2、配置文件的bean标签设置property标签
<!--IOC通过property标签手动装配(注入):Set方法注入name:bean对象中属性字段的名称ref:指定bean标签的id属性值value:具体的值(基本类型 常用对象|日期 集合)--><bean id="userService" class="com.shsxt.service.UserService"><!--业务对象 注入--><property name="userDao" ref="userDao"/><property name="studentDao" ref="studentDao"/><!--常用对象String 注入--><property name="host" value="192.168.1.109"/><!--基本类型注入--><property name="port" value="8080"/><!--List集合 注入--><property name="list"><list><value>上海</value><value>北京</value><value>杭州</value></list></property><!--Set集合注入--><property name="set"><set><value>上海SH</value><value>北京BJ</value><value>杭州HZ</value></set></property><!--Map注入--><property name="map"><map><entry><key><value>周杰伦</value></key><value>我是如此相信</value></entry><entry><key><value>林俊杰</value></key><value>可惜没如果</value></entry><entry><key><value>陈奕迅</value></key><value>十年</value></entry></map></property><!--Properties注入--><property name="properties"><props><prop key="上海">东方明珠</prop><prop key="北京">天安门</prop><prop key="杭州">西湖</prop></props></property></bean>
构造器注入
Java代码:
提供带参构造器
public class UserService02 {private UserDao02 userDao02;/*public UserService02(UserDao02 userDao02) {this.userDao02 = userDao02;}*/private StudentDao02 studentDao02;/*public UserService02(UserDao02 userDao02, StudentDao02 studentDao02) {this.userDao02 = userDao02;this.studentDao02 = studentDao02;}*/private String uname;public UserService02(UserDao02 userDao02, StudentDao02 studentDao02, String uname) {this.userDao02 = userDao02;this.studentDao02 = studentDao02;this.uname = uname;}public void test(){System.out.println("UserService02 Test...");userDao02.test();studentDao02.test();System.out.println(uname);}}
XML配置:
<!--IOC通过构造器注入:通过constructor-arg标签进行注入name:属性名称ref:指定bean标签的id属性值value:基本类型 常用对象的值index:构造器中参数的下标,从0开始--><bean id="userService02" class="com.shsxt.service.UserService02"><constructor-arg name="userDao02" ref="userDao02"></constructor-arg><constructor-arg name="studentDao02" ref="studentDao02"></constructor-arg><constructor-arg name="uname" value="admin"></constructor-arg></bean><bean id="userDao02" class="com.shsxt.dao.UserDao02" ></bean><bean id="studentDao02" class="com.shsxt.dao.StudentDao02" ></bean>
可能出现的问题:循环依赖
Java代码:
public class AccountService {private RoleService roleService;public AccountService(RoleService roleService) {this.roleService = roleService;}public void test() {System.out.println("AccountService Test...");}
}public class RoleService {private AccountService accountService;public RoleService(AccountService accountService) {this.accountService = accountService;}public void test() {System.out.println("RoleService Test...");}
}
XML配置:
<!--如果多个bean对象中互相注入,则会出现循环依赖的问题可以通过set方法注入解决-->
<bean id="accountService" class="com.shsxt.service.AccountService"><constructor-arg name="roleService" ref="roleService"/>
</bean><bean id="roleService" class="com.shsxt.service.RoleService"><constructor-arg name="accountService" ref="accountService"/>
</bean>
如何解决:将构造器注入改为set方法注入
public class AccountService {private RoleService roleService;/* public AccountService(RoleService roleService) {this.roleService = roleService;}*/public void setRoleService(RoleService roleService) {this.roleService = roleService;}public void test() {System.out.println("AccountService Test...");}
}public class RoleService {private AccountService accountService;/* public RoleService(AccountService accountService) {this.accountService = accountService;}*/public void setAccountService(AccountService accountService) {this.accountService = accountService;}public void test() {System.out.println("RoleService Test...");}
}
<!--修改为set方法注入--><bean id="accountService" class="com.shsxt.service.AccountService"><property name="roleService" ref="roleService"/></bean><bean id="roleService" class="com.shsxt.service.RoleService"><property name="accountService" ref="accountService"/></bean>
静态工厂注入(了解)
1、定义工厂类
public class StaticFactory {// 定义静态方法public static TeacherService createTeacherService() {return new TeacherService();}
}
2、在配置文件中设置bean标签,指定工厂对象并设置对应的方法
<!--静态工厂注入--><bean id="teacherService" class="com.shsxt.factory.StaticFactory" factory-method="createTeacherService"></bean>
实例化工厂注入(了解)
1、定义工厂类
public class InstanceFactory {public TeacherService createService() {return new TeacherService();}
}
2、声明工厂bean标签,声明bean对象,指明工厂对象和工厂方法
<!--实例化工厂注入-->
<bean id="instanceFactory" class="com.shsxt.factory.InstanceFactory"></bean>
<bean id="teacherService" factory-bean="instanceFactory" factory-method="createService"></bean>
Spring IOC 自动装配(注入)
1、准备环境(修改配置文件)
<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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">
2、开启自动化注入
<!--开启自动化装配(注入)-->
<context:annotation-config/>
3、给注入的bean对象添加注解
@Resource注解
@Resource注解实现自动注入(反射)
1、默认根据属性字段名称查找对应的bean对象 (属性字段的名称与bean标签的id属性值相等)
2、如果属性字段名称未找到,则会通过类型(Class类型)查找
3、属性可以提供set方法,也可以不提供set方法
4、注解可以声明在属性级别 或 set方法级别
5、@Resource可以设置name属性,name属性值必须与bean的id属性值一致;如果设置了name属性值,就只会按照name属性值查找bean对象
6、当注入接口时,如果接口只有一个实现则正常实例化;如果接口存在多个实现,则需要使用name属性指定需要被实例化的bean对象
private UserDao ud;
@Resource
public void setUd(UserDao ud) {this.ud = ud;
}@Resource(name = "userDao03")
private IUserDao iUserDao;
@AutoWired注解
@Autowired注解实现自动化注入:1、默认通过类型(Class类型)查找bean对象 与属性字段的名称无关2、属性可以提供set方法,也可以不提供set方法3、注解可以声明在属性级别 或 set方法级别4、可以添加@Qualifier结合使用,通过value属性值查找beam对象(value属性值必须要设置,且值要与bwan标签的id属性值对应)
@Autowired
@Qualifier(value = "accountDao")
private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;
}
Spring Ioc扫描器
Spring IOC扫描器作用:bean对象统一进行管理,简化开发配置,提高开发效率1、设置自动化扫描的范围如果bean对象未在指定包范围,即使声明另外注解,也无法实例化2、使用指定的注解(声明在类级别) bean对象的id属性默认是 类的首字母小写Dao层:@RepositoryService层:@ServiceController层:@Controller任意类:@Component注:开发过程中建议按照指定规则声明注解
1、设置自动化扫描的范围
<!-- 设置自动化扫描的范围 --><context:component-scan base-package="com.shsxt"/>
2、使用特定的注解
@Controller
public class ResourceController {@Autowiredprivate ResourceService resourceService;public void test() {System.out.println("ResourceController...");resourceService.test();}
}
@Service
public class ResourceService {@Resourceprivate ResourceDao resourceDao;public void test() {System.out.println("ResourceService...");resourceDao.test();}
}
@Repository
public class ResourceDao {public void test() {System.out.println("ResourceDao...");}
}
@Component
public class PropertyUtils {public void test(){System.out.println("PropertyUtils...");}
}
Bean的作用域
singleton作用域
prototype作用域
web作用域
Bean的作用域scope:设置bean对象的作用域(singleton或prototype),默认singletonsingleton单例作用域Spring IOC容器在实例化对象时,会将单例对象设置到单例缓存池中lazy-init属性(懒加载)如果为false,则在IOC容器启动时会实例化bean对象,默认false如果为true,则IOC容器启动时不会实例化Bean对象,在使用bean对象时才会实例化lazy-init设置为false有什么好处?1、可以提前发现潜在的配置问题2、Bean 对象存在于缓存中,使用时不用再去实例化bean,加快程序运行效率什么对象适合作为单例对象?无状态的对象 (不存在会改变对象状态的成员变量)controller层、service层、dao层prototype原型作用域Spring IOC容器在实例化对象时,不会将单例对象设置到单例缓存池中,每一次实例都是一个新的对象Web作用域request作用域在每一次请求实例化一个bean对象session作用域在每一次有效会话实例化一个bean对象globalSession作用域类似于session
Bean的生命周期
Bean的生命周期Bean的生命周期包括Bean的定义、初始化、使用和销毁4个阶段定义通过配置文档的方式来定义Bean的初始化默认在IOC容器加载时,就实例化对象Spring bean 初始化有两种方式:I.在配置文档中通过指定 init-method 属性来完成。II.实现org.springframework.beans.factory.InitializingBean接口。使用I.使用BeanFactoryII.使用ApplicationContext销毁步骤一:实现销毁方式(Spring容器会维护bean对象的管理,可以指定bean对象的销毁所要执行的方法)<bean id="userServiceImpl"class="com.shsxt.service.impl.UserServiceImpl" init-method="init" destroy-method="destroy"></bean>步骤二:过AbstractApplicationContext 对象,调用其close方法实现bean的销毁过程。AbstractApplicationContext ctx=new ClassPathXmlApplicationContext("Spring-application.xml");ctx.close();
IOC-控制反转和依赖注入将对象实例化的创建过程转交给外部容器(IOC容器 充当工厂角色)去负责;属性赋值的操作;
Spring第三天
Spring AOP 面向切面编程
一、代理模式
为某一个对象(委托类)提供一个代理(代理类),用来控制对这个对象的访问。委托类和代理类有一个共同繁荣父类或父接口。代理类会对请求做预处理、过滤,将请求分配给指定对象。
生活中常见的代理情况:
租房中介、婚庆公司等
代理模式的两个设计原则:
1. 代理类 与 委托类 具有相似的行为(共同)
2. 代理类增强委托类的行为
常用的代理模式:
静态代理 和 动态代理
二、静态代理
1、静态代理的三要素(婚庆公司)
a、有共同的行为(结婚) - 接口
b、目标角色(新郎) - 实现行为
c、代理角色(婚庆公司) - 实现行为 增强目标对象行为
2、静态代理的特点
1、在应用程序执行前就得到目标角色
2、代理对象会增强目标对象的行为
3、目标角色固定
4、有可能存在多个代理 引起"类爆炸"(缺点)
3、静态代理的实现
1. 定义行为(共同) 定义接口
/*** 定义行为*/
public interface Marry {public void toMarry();
}
2. 目标对象(实现行为)
/*** 静态代理 ——> 目标对象*/
public class You implements Marry {// 实现行为@Overridepublic void toMarry() {System.out.println("我要结婚了...");}
}
3. 代理对象(实现行为、增强目标对象的行为)
/*** 静态代理 ——> 代理对象*/
public class MarryCompanyProxy implements Marry {// 目标对象private Marry marry;// 通过构造器将目标对象传入public MarryCompanyProxy(Marry marry) {this.marry = marry;}// 实现行为@Overridepublic void toMarry() {// 增强行为before();// 执行目标对象中的方法marry.toMarry();// 增强行为after();}/*** 增强行为*/private void after() {System.out.println("新婚快乐,早生贵子!");}/*** 增强行为*/private void before() {System.out.println("场地正在布置中...");}
}
4. 通过代理对象实现目标对象的功能
// 目标对象
You you = new You();
// 代理对象
MarryCompanyProxy marryCompanyProxy = new MarryCompanyProxy(you);
// 通过代理对象调用目标对象中的方法
marryCompanyProxy.toMarry();
三、动态代理
1. 动态代理的特点
1、在应用程序执行时动态创建目标对象
2、代理对象会增强目标对象的行为
3、目标对象不固定
注:JDK动态代理的目标对象必须有接口实现
2. JDK动态代理
newProxyInstance
/*返回一个指定接口的代理类的实例方法调用分派到指定的调用处理程序。 (返回代理对象)loader:类加载器interfaces:对象实现的接口数组h:InvocationHandler接口 */ public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
获取代理对象
public class JdkHandler implements InvocationHandler {// 目标对象private Object target; // 目标对象的类型不固定,创建时动态生成// 通过构造器将目标对象赋值public JdkHandler(Object target) {this.target = target;}/*** 1、调用目标对象的方法(返回Object)* 2、增强目标对象的行为* @param proxy 代理类的实例对象* @param method 目标对象的方法* @param args 目标对象的方法形参* @return* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 增强行为System.out.println("==============方法前执行");// 调用目标对象的方法(返回Object)Object result = method.invoke(target,args);// 增强行为System.out.println("方法后执行==============");return result;}/*** 得到代理对象* public static Object newProxyInstance(ClassLoader loader,* Class<?>[] interfaces,* InvocationHandler h)* loader:类加载器* interfaces:对象实现的接口数组* h:InvocationHandler接口*** @return*/public Object getProxy() {return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);} }
通过代理对象实现目标对象的功能
// 目标对象 You you = new You(); // 获取代理对象 JdkHandler jdkHandler = new JdkHandler(you); Marry marry = (Marry) jdkHandler.getProxy(); // 通过代理对象调用目标对象中的方法 marry.toMarry();
3. CGLIB动态代理
动态代理:
继承思想
1、在pom.xml文件中引入cglib的相关依赖
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version>
</dependency>
2、定义类,实现MethodInterceptor接口
public class CglibInterceptor implements MethodInterceptor {// 目标对象private Object target;// 通过构造器传入目标对象public CglibInterceptor(Object target) {this.target = target;}/*** 获取代理对象* @return*/public Object getProxy() {// 通过Enhancer对象的create()方法可以生成一个类Enhancer enhancer = new Enhancer();// 设置父类 (将目标类作为其父类)enhancer.setSuperclass(target.getClass());// 设置回调,调用回调对象中的enhancer.setCallback(this);return enhancer.create();}/*** 1、目标对象的方法调用* 2、增强行为* @param o* @param method* @param objects* @param methodProxy* @return* @throws Throwable*/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {// 增强行为System.out.println("==============方法前执行");// 调用目标对象的方法(返回Object)Object result = methodProxy.invoke(target,objects);// 增强行为System.out.println("方法后执行==============");return result;}}
3、调用方法
// 目标对象
You you = new You();
CglibInterceptor cglibInterceptor = new CglibInterceptor(you);
Marry marry = (Marry) cglibInterceptor.getProxy();
marry.toMarry();User user = new User();
CglibInterceptor cglibInterceptor = new CglibInterceptor(user);
User u = (User) cglibInterceptor.getProxy();
u.test();
4. JDK动态代理 和 Cglib动态代理
1. JDK动态代理实现接口,Cglib动态代理继承思想
2. JDK动态代理(目标对象存在接口时)执行效率高于Ciglib
3. 如如果目标对象有接口实现,选择JDK代理,如果没有接口实现选择Cglib代理
四、Spring AOP
需要对以下功能进行日志记录,事务处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SlqWWS31-1581090934907)(F:/SHSXT/Java%E9%AB%98%E7%BA%A7/%E7%AC%94%E8%AE%B0/Java33/images/1576770254892.png)]
假如没有AOP,在做日志和事务处理的时候,我们会在每个方法中添加相关处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uogt8l9v-1581090934908)(F:/SHSXT/Java%E9%AB%98%E7%BA%A7/%E7%AC%94%E8%AE%B0/Java33/images/1576769002873.png)]
但大多数的代码是相同的,为了实现代码复用,我们可能把日志和事务处理抽离成一个新的方法。但是这样我们仍然必须手动插入这些方法。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6rnuoLu7-1581090934910)(F:/SHSXT/Java%E9%AB%98%E7%BA%A7/%E7%AC%94%E8%AE%B0/Java33/images/1576769398313.png)]
但这样两个方法就是强耦合的,假如此时我们不需要这个功能了,或者想换成其他功能,那么就必须一个个修改。
通过代理模式,可以在指定位置执行对应流程。这样就可以将一些横向的功能抽离出来形成一个独立的模块,然后在指定位置插入这些功能。这样的思想,被称为面向切面编程,即AOP。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4DBoqNhD-1581090934911)(F:/SHSXT/Java%E9%AB%98%E7%BA%A7/%E7%AC%94%E8%AE%B0/Java33/images/1576767721274.png)]
1. 什么是AOP?
AOP:Aspect Oriented Programming 面向切面编程
AOP关注不是某一个类或某些方法;控制大量资源,关注的是大量的类和方法。
2. AOP能做什么?
AOP主要应用于日志记录,性能统计,安全控制,事务处理等方面,实现公共功能性的重复使用。
3. AOP的特点
1. 降低模块与模块之间的耦合度,提高业务代码的聚合度。(高内聚低耦合)
2. 提高了代码的复用性。
3. 提高系统的扩展性。(高版本兼容低版本)
4. 可以在不影响原有的功能基础上添加新的功能
4. AOP的底层实现
动态代理(JDK + CGLIB)
5. AOP基本概念
1. Joinpoint(连接点)
匹配到的每一个方法,spring aop一个连接点即代表一个方法的执行
2. Pointcut(切入点)
匹配规则。规定什么方法被拦截、需要处理什么方法
3. Advice(通知)
拦截到每一个方法(每一个连接点)所执行的操作
前置通知:在方法被执行之前通知
最终通知(finally):无论方法执行过程中是否出现异常,最后都会通知
返回通知:当方法(无异常)执行完毕后通知
异常通知:当方法执行时出现异常通知
环绕通知:可以替代上面四种 有返回值的通知
4. Aspect(切面)
切入点和通知的抽象 (与面向对象中的 类 相似)
定义 切入点和通知 (切入点定义了要拦截哪些类的哪些方法,通知则定义了拦截过方法后要做什么)
5. Target(目标对象)
被代理的目标对象
6. Weave(织入)
将切面应用到目标对象并生成代理对象的这个过程即为织入
7. Introduction(引入)
在不修改原有应用程序代码的情况下,在程序运行期为类动态添加方法或者字段的过程称为引入
五、Spring AOP实现
1. Spring AOP环境搭建
a、jar 包坐标引入
<!--Spring AOP-->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.9</version>
</dependency>
b、添加spring.xml的配置
添加命名空间
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd
2. 注解实现
- 定义切面
/*** 切面* 切入点和通知的抽象 (与面向对象中的 类 相似)* 定义 切入点和通知 (切入点定义了要拦截哪些类的哪些方法,通知则定义了拦截过方法后要做什么)*/
@Component // 将对象交给IOC容器去实例化
@Aspect // 声明当前类是一个切面
public class LogCut {/*** 切入点:* 匹配规则。规定什么方法被拦截、需要处理什么方法* 定义切入点* @Pointcut("匹配规则")* 语法:* @Pointcut("execution (* com.shsxt.service..*.*(..) )")* 第一个* 代表的是方法的修饰范围 (private、protected、public) *表示所有范围* com.shsxt.service..*.*(..)* 匹配com.shsxt.service包下及子包下所有的类的所有方法* com.shsxt.service.*.*(..)* 匹配com.shsxt.service包下所有的类的所有方法**/@Pointcut("execution (* com.shsxt.service..*.*(..) )")public void cut(){}/*** 声明前置通知 并将通知应用到定义的切入点上* 目标类方法执行前 执行该通知**/@Before(value = "cut()")public void before() {System.out.println("前置通知.....");}/*** 声明返回通知 并将通知应用到定义的切入点上* 目标类方法(无异常)执行后 执行该通知**/@AfterReturning(value = "cut()")public void afterReturn() {System.out.println("返回通知.....");}/*** 声明最终通知 并将通知应用到定义的切入点上* 目标类方法(无异常或有异常)执行后 执行该通知**/@After(value = "cut()")public void after() {System.out.println("最终通知.....");}/*** 声明异常通知 并将通知应用到定义的切入点上* 目标类方法出现异常时 执行该通知*/@AfterThrowing(value="cut()",throwing = "e")public void afterThrow(Exception e) {System.out.println("异常通知....." + " 异常原因:" + e.getCause());}/*** 声明环绕通知 并将通知应用到切入点上* 方法执行前后 通过环绕通知定义相应处理* 需要通过显式调用对应的方法,否则无法访问指定方法 (pjp.proceed();)* @param pjp* @return*/@Around(value = "cut()")public Object around(ProceedingJoinPoint pjp) {System.out.println("前置通知...");Object object = null;try {object = pjp.proceed();System.out.println(pjp.getTarget() + "======" + pjp.getSignature());// System.out.println("返回通知...");} catch (Throwable throwable) {throwable.printStackTrace();System.out.println("异常通知...");}System.out.println("最终通知...");return object;}}
- 配置文件(spring.xml)
<!--配置AOP代理--><aop:aspectj-autoproxy/>
3. XML实现
- 定义切面
*** 切面* 切入点和通知的抽象 (与面向对象中的 类 相似)* 定义 切入点和通知 (切入点定义了要拦截哪些类的哪些方法,通知则定义了拦截过方法后要做什么)*/
@Component // 将对象交给IOC容器去实例化
public class LogCut02 {public void cut(){}/*** 声明前置通知 并将通知应用到定义的切入点上* 目标类方法执行前 执行该通知**/public void before() {System.out.println("前置通知.....");}/*** 声明返回通知 并将通知应用到定义的切入点上* 目标类方法(无异常)执行后 执行该通知**/public void afterReturn() {System.out.println("返回通知.....");}/*** 声明最终通知 并将通知应用到定义的切入点上* 目标类方法(无异常或有异常)执行后 执行该通知**/public void after() {System.out.println("最终通知.....");}/*** 声明异常通知 并将通知应用到定义的切入点上* 目标类方法出现异常时 执行该通知*/public void afterThrow(Exception e) {System.out.println("异常通知....." + " 异常原因:" + e.getCause());}/*** 声明环绕通知 并将通知应用到切入点上* 方法执行前后 通过环绕通知定义相应处理* 需要通过显式调用对应的方法,否则无法访问指定方法 (pjp.proceed();)* @param pjp* @return*/public Object around(ProceedingJoinPoint pjp) {System.out.println("前置通知...");Object object = null;try {object = pjp.proceed();System.out.println(pjp.getTarget() + "======" + pjp.getSignature());// System.out.println("返回通知...");} catch (Throwable throwable) {throwable.printStackTrace();System.out.println("异常通知...");}System.out.println("最终通知...");return object;}}
- 配置文件(spring.xml)
<!--aop相关配置-->
<aop:config><!--aop切面--><aop:aspect ref="logCut02"><!-- 定义aop 切入点 --><aop:pointcut id="cut" expression="execution(* com.shsxt.service..*.*(..))"/><!-- 配置前置通知 指定前置通知方法名 并引用切入点定义 --><aop:before method="before" pointcut-ref="cut"/><!-- 配置返回通知 指定返回通知方法名 并引用切入点定义 --><aop:after-returning method="afterReturn" pointcut-ref="cut"/><!-- 配置异常通知 指定异常通知方法名 并引用切入点定义 --><aop:after-throwing method="afterThrow" throwing="e" pointcut-ref="cut"/><!-- 配置最终通知 指定最终通知方法名 并引用切入点定义 --><aop:after method="after" pointcut-ref="cut"/><!-- 配置环绕通知 指定环绕通知方法名 并引用切入点定义 --><aop:around method="around" pointcut-ref="cut"/></aop:aspect>
</aop:config>
Spring第四天
Spring JDBC
1. SpringJDBC 环境搭建
1.1 引入依赖(添加坐标)
<!--junit单元测试-->
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency>
<!-- spring 测试环境 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>4.3.2.RELEASE</version><scope>test</scope>
</dependency><!-- spring 框架坐标依赖添加 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.3.2.RELEASE</version>
</dependency><!-- aop -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.9</version>
</dependency><!-- mysql 驱动包 -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.39</version>
</dependency>
<!-- c3p0 连接池 -->
<dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1.2</version>
</dependency><!-- spring jdbc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>4.3.2.RELEASE</version>
</dependency><!-- spring事物 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>4.3.2.RELEASE</version>
</dependency>
1.2 添加db.properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_jdbc?useUnicode=true&characterEncoding=utf8
jdbc.user=root
jdbc.password=root
1.3 添加spring.xml文件
- 设置扫描器范围
- 加载properties 配置文件
- 配置成c3p0 数据源
- 配置JdbcTemplate 模板
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--设置扫描器范围--><context:component-scan base-package="com.shsxt"/><!-- 加载properties 配置文件 --><context:property-placeholder location="db.properties"/><!-- 配置c3p0 数据源 --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driver}"/><property name="jdbcUrl" value="${jdbc.url}"/><property name="user" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/></bean><!-- jdbcTemplate 配置 --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean></beans>
1.4 测试JDBC
@Test
public void testQueryCount() {// 得到Spring上下文环境ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");// 得到模板类 JdbcTemplate对象JdbcTemplate jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate");Integer count = jdbcTemplate.queryForObject("select count(1) from account",Integer.class);Integer count1 = jdbcTemplate.queryForObject("select count(1) from account where userId = ?",Integer.class,1);System.out.println(count+"-------"+count1);
}
简易版:
使用注解方式
@RunWith(SpringJUnit4ClassRunner.class)
将junit测试加到spring环境中
@ContextConfiguration(locations = {“classpath:spring.xml”})
设置要加载的资源文件
- 定义父类
@RunWith(SpringJUnit4ClassRunner.class) // 将junit测试加到spring环境中
@ContextConfiguration(locations = {"classpath:spring.xml"}) // 设置要加载的资源文件
public class TestBase {}
- 继承父类
public class SpringJdbcTest extends TestBase {@Resourceprivate JdbcTemplate jdbcTemplate;@Testpublic void testQueryCount() {Integer count = jdbcTemplate.queryForObject("select count(1) from account",Integer.class);Integer count1 = jdbcTemplate.queryForObject("select count(1) from account where userId = ?",Integer.class,1);System.out.println(count+"-------"+count1);
}
<property name="jdbcUrl" value="${jdbc.url}"/><property name="user" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/>
</bean><!-- jdbcTemplate 配置 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property>
</bean>
```
1.4 测试JDBC
@Test
public void testQueryCount() {// 得到Spring上下文环境ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");// 得到模板类 JdbcTemplate对象JdbcTemplate jdbcTemplate = (JdbcTemplate) ac.getBean("jdbcTemplate");Integer count = jdbcTemplate.queryForObject("select count(1) from account",Integer.class);Integer count1 = jdbcTemplate.queryForObject("select count(1) from account where userId = ?",Integer.class,1);System.out.println(count+"-------"+count1);
}
简易版:
使用注解方式
@RunWith(SpringJUnit4ClassRunner.class)
将junit测试加到spring环境中
@ContextConfiguration(locations = {“classpath:spring.xml”})
设置要加载的资源文件
- 定义父类
@RunWith(SpringJUnit4ClassRunner.class) // 将junit测试加到spring环境中
@ContextConfiguration(locations = {"classpath:spring.xml"}) // 设置要加载的资源文件
public class TestBase {}
- 继承父类
public class SpringJdbcTest extends TestBase {@Resourceprivate JdbcTemplate jdbcTemplate;@Testpublic void testQueryCount() {Integer count = jdbcTemplate.queryForObject("select count(1) from account",Integer.class);Integer count1 = jdbcTemplate.queryForObject("select count(1) from account where userId = ?",Integer.class,1);System.out.println(count+"-------"+count1);
}
史上最全讲解:Spring详解相关推荐
- 史上最全数据库中间件详解
导读:本文详细介绍了中间件,主要从数据库拆分过程及挑战.主流数据库中间件设计方案.读写分离核心要点.分库分表核心要点展开说明. 1. 数据库拆分过程及挑战 垂直拆分.读写分离.分库分表(水平拆分).每 ...
- 史上最全 JVM 大全详解、java 程序员细节到极致的一次,魔鬼
前言 作为 Java 的从业者,在找工作的时候,一定会被问及关于 JVM 相关的知识. JVM 知识的掌握程度,在很多面试官眼里是候选人技术深度的一个重要评判标准.而大多数人可能没有对 JVM 的实际 ...
- 史上最全 JVM 大全详解!java 程序员细节到极致的一次,魔鬼
前言 作为 Java 的从业者,在找工作的时候,一定会被问及关于 JVM 相关的知识. JVM 知识的掌握程度,在很多面试官眼里是候选人技术深度的一个重要评判标准.而大多数人可能没有对 JVM 的实际 ...
- 史上最全测试流程详解----超详细
前言----- 对于测试流程基本很多做过测试的大牛,小哥哥,小姐姐都能说出个十之八九,但是对于细节,可能还需要一些整理文件,这不,我整理了一些测试的全部流程,希望能给大家带来帮助,有不妥的地方,请大家 ...
- java二叉树原理_史上最全二叉树遍历详解(Java实现,原理相同)
二叉树遍历方法合集: 最近在LeetCode力扣上刷数据结构的二叉树合集,遇到的二叉树遍历方法,于是想理解透彻.本文讲解了二叉树遍历的四种方法,前.中.后序遍历. 对应题目: 94.二叉树的中序遍历 ...
- 接地脚是什么意思_史上最全的接地系统详解,值得收藏
接地一直是很多弱电朋友的难点,主要还是做接地的工程不多,这方面一直陆陆续续的朋友在讨论过,那么今天我们一起来对接地进行详细了解. 有人问:为什么回路电流走零线不走地线,而漏电流走地线不走零线,零线地线 ...
- 史上最全1000字详解计算机网络必备知识--因特网笔记整理,附上10张精美配图!
计算机网络概述 已同步微信公众号:乐享Coding,期待你的关注! 「网络」(Network)由若干结点(Node)和连接这些结点的链路(Link)组成. 多个网络可以通过路由器互连起来,这样就构成了 ...
- 史上最全IO模型详解
操作系统 在介绍IO模型之前,先要介绍内核态和用户态.在操作系统中,因为有些操作指令是不能开放给用户的,比如读取磁盘,清除内存,读写网卡数据.这样用户态程序不能随便操作内核地址,即使用户程序崩溃了,对 ...
- 史上最简单MySQL教程详解(进阶篇)之索引及失效场合总结
史上最简单MySQL教程详解(进阶篇)之索引及其失效场合总结 什么是索引及其作用 索引的种类 各存储引擎对于索引的支持 简单介绍索引的实现 索引的设置与分析 普通索引 唯一索引(Unique Inde ...
最新文章
- 面对对象的程序设计初探总结
- Java并发编程(十三)同步容器类
- ionic + cordova 配置和开发过程中的一些问题
- java按照商品价格排序_按照指定的类型排序
- java jni调用dll_浅谈JNI的使用--java调用dll(原创)
- 7a系列mrcc xilinx_artix-7A200T的输入时钟(50M)管脚接到MRCC的N端了,怎么解决?
- Windows10 热点(WIFI)配置教程
- html5拖放文件,HTML5是否允许拖放拖放文件夹或文件夹树?
- Tensorflow之计算tensor平均值
- Linux音频驱动-声音采集过程
- 传递参数安全验证代码示例
- WeakHashMap回收时机结合JVM 虚拟机GC的一些理解
- 微信小程序项目源代码精品微信小程序电子书城销售系统|商城|电商系统
- matlab产生大气湍流,一种大气湍流模拟装置的制造方法
- 百度云文字识别demo
- 数据库的方向 - 行vs列
- 最大连续子数组和python_连续子数组的最大和(python)
- 使用powershell Client进行有效dy
- reactjs中使用高德地图计算两个经纬度之间的距离
- Uconn DataMining Math5671 课程小记(1)
热门文章
- 护眼灯哪些牌子好?央视推荐的护眼台灯
- 特征工程系列(一):特征工程的概念/特征的处理
- 对于python中range函数的使用
- BIM+GIS技术融合发展 成为工程规划建设新热点
- DHCP-小结(拓展 网卡文件的配置)
- Freemarker导出word图片不显示可能的原因
- Appium 自动化用例设计(TESTNG 篇)
- ‘kaggle视频游戏销售数据的可视化和分析‘项目实现
- 电子科技大学 易查分网站 爬虫 批量爬取成绩
- Linux环境安装python3报错:“HTTP Error 416 Requested Range Not Satisfiable 正在尝试其它镜像”的解决方法