Spring
Posted xue_yun_xiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring相关的知识,希望对你有一定的参考价值。
一、什么是AOP?
Aop 就是面向切面编程
通俗点:就是用一个切面类去拦截 你想拦截的方法,用以一个切面 切向 拦截方法
切面:就是一个类,内部封装了抽取了公共方法(日志,鉴权登录,拦截,过滤)。
面向切面编程作用:
1.包程序中重复代码,冗余的代码,需要统一处理的代码放在切面公共方法
2.提高程序的可维护性,在不改变原有代码情况下,对目标方法进行增强
Proxy:代理,就是aop 生成的代理对象
Advice(通知/增强处理):通知就是切面中封装的方法
Target Object(目标对象):要拦截的对象,代理的对象
Aspect(切面):切面就是一个类,封装了公共的方法(通知)
Joinpoint(连接点):就是普通的方法
Pointcut(切入点):就是切面和拦截的方法交会的方法(连接点)
切入点就是连接点,连接点不一定时切入点。
Weaving(织入):将切面 切向切入点(拦截的方法)过程,生成代理对象就是织入
二、SpringAop 基于ProxyFactoryBean实现
ProxyFactoryBean:作用就是产生代理对象,实现了 FactoryBean接口
FactoryBean & BeanFacotry?
FactoryBean:生成对象
BeanFacotry:spring 核心容器,获取对象(getBean(""))
1、引入依赖
<properties>
<!--在当前pom 或者父类pom 中声明属性 -->
<spirng.version>5.0.16.RELEASE</spirng.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spirng.version}</version>
</dependency>
<!-- 导入spring aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spirng.version}</version>
</dependency>
</dependencies>
2、创建切面,并加入到容器
/**
* 创建一个切面
*
*/
public class MyAspect implements MethodInterceptor {
// 公共方法------>通知
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("即将执行方法:"+methodInvocation.getMethod().getName());
// 调用目标方法执行 获取结果
Object result = methodInvocation.proceed();
System.out.println("切面打印结果:"+result);
return result;
}
}
3、织入
<?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="studentDao" class="com.qfedu.dao.impl.StudentDaoImpl"></bean>
<!--
将切面 实例 加入到容器中
-->
<bean id="myAspect" class="com.qfedu.aspect.spring.MyAspect"></bean>
<!--
将界面 切向 连接点 这个过程就是织入
ProxyFactoryBean :就是创建代理对象 实现了 FactoryBean接口
-->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--
target 指定代理对象 的目标对象
-->
<property name="target" ref="studentDao"></property>
<!--
proxyInterfaces 如果代理的目标对象有实现接口 写上,没有接口不写
-->
<property name="proxyInterfaces" value="com.qfedu.dao.IStudentDao"></property>
<!--
interceptorNames 指定切面 切记:使用value 指定
-->
<property name="interceptorNames" value="myAspect"></property>
<!--
proxyTargetClass 指定产生代理对象的方式
true: 代表强制使用cglib
false: 目标对象实现接口 使用jdk,没有实现接口使用cglib
-->
<property name="proxyTargetClass" value="true"></property>
</bean>
</beans>
4、测试
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
// 目标对象
// IStudentDao studentDao = (IStudentDao) applicationContext.getBean("studentDao");
// System.out.println("student:"+studentDao.findStudentById(200));
// 通过 代理对象 ProxyFactoryBean 获取代理对象
IStudentDao studentDao = (IStudentDao) applicationContext.getBean("proxyFactoryBean");
System.out.println("student:"+studentDao.findStudentById(200));
}
三、SpringAop 基于Aspectj 实现
spring Aop 引入优秀的 AspectJ 框架,更加丰富了springaop 的功能
AspectJ 实现分两种:
-xml 实现
-注解实现
xml 实现
1、引入依赖
<properties>
<!--在当前pom 或者父类pom 中声明属性 -->
<spirng.version>5.0.16.RELEASE</spirng.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spirng.version}</version>
</dependency>
<!-- 导入spring aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spirng.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
</dependencies>
2、创建切面
package com.qfedu.aspect.aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 基于AspectJ 的切面
*
* 切面:有公共的方法组成,公共的方法就是通知
* 通知分为:
* 前置通知
* 后置通知
* 环绕通知
* 异常通知
* 最终通知
*
*/
public class MyAspectXml {
/**
* 前置通知
* 调用目标方法前调用
* JoinPoint 连接点 中的切点
* @param joinPoint
*/
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知:"+joinPoint.getSignature().getName());
}
/**
* 环绕通知 :决定目标对象是否执行 拦截发生在 环绕不调用joinPoint.proceed(); 就是拦截
* @param joinPoint
*/
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知---前:"+joinPoint.getSignature().getName());
// Object result = null;
// 调用 目标对象执行相应的方法
Object result = joinPoint.proceed();
System.out.println("环绕通知---result"+result);
System.out.println("环绕通知---后"+joinPoint.getSignature().getName());
return result;
}
/**
* 最终通知 无论方法 是否异常 都会通知
* @param joinPoint
*/
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知:"+joinPoint.getSignature().getName());
}
/**
* 后置通知 : 可以获取目标执行的结果 ,如果发生异常 不调用
* @param joinPoint
*/
public void myAfterReturning(JoinPoint joinPoint,Object result){
System.out.println("后置通知:"+joinPoint.getSignature().getName());
System.out.println("后置通知--result:"+result);
}
/**
* 异常通知 :不发生异常不调用
*
* Throwable e 接收异常信息
* @param joinPoint
*/
public void myThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("异常通知"+joinPoint.getSignature().getName());
System.out.println("异常通知--异常信息:"+e.getMessage());
}
}
3、织入
<?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 https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--目标 加入到容器
如果目标对象 被切面拦截 目标对象就会被 代理对象替换(通过后置处理器替换)
-->
<bean id="studentDao" class="com.qfedu.dao.impl.StudentDaoImpl"></bean>
<!--
声明 切面 加入容器中
-->
<bean id="myAspectXml" class="com.qfedu.aspect.aspectj.MyAspectXml"></bean>
<!--
织入
-->
<aop:config>
<!-- 声明切面中的切点
expression="execution()" 切点表达式 就是要拦截方法的集合
声明在切面中 只能被当前切面使用,如果声明在 <aop:config> 可以被所有切面使用
-->
<aop:pointcut id="myPointcut" expression="execution(* com.qfedu.dao.*.*.*(..))"/>
<!-- 切面进行织入也就是将切面 和 切入点(拦截的方法发生关联)
ref="myAspectXml" 引用切面
-->
<aop:aspect ref="myAspectXml">
<!--
将切面中的 前置通知 和 切点绑定
-->
<aop:before method="myBefore" pointcut-ref="myPointcut"></aop:before>
<!--
最终通知
-->
<aop:after method="myAfter" pointcut-ref="myPointcut"></aop:after>
<!--
后置通知 :获取目标对象执行方法的结果 returning=""
-->
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut" returning="result"></aop:after-returning>
<!--
环绕通知: 决定是否调用目标对象
-->
<aop:around method="myAround" pointcut-ref="myPointcut"></aop:around>
<!--
throwing="e" 将异常信息传递给 异常通知myThrowing
-->
<aop:after-throwing method="myThrowing" pointcut-ref="myPointcut" throwing="e"></aop:after-throwing>
</aop:aspect>
</aop:config>
</beans>
4、测试
public class MyAspectXmlTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean_aspectj_xml.xml");
// 获取目标对象
IStudentDao studentDao = (IStudentDao) applicationContext.getBean("studentDao");
System.out.println("studentDao:"+studentDao.findStudentById(300));
}
}
注解实现
1、创建切面
/**
* 使用注解完成 aspectj aop
*/
@Component // 将当前切面加入到容器中
@Aspect // 声明当前对象 是一个切面 相当于xml <aop:aspect @Aspect 也需要激活 <aop:aspectj-autoproxy>
public class MyAspectAnnotation {
// @Pointcut("execution(* com.qfedu.dao.*.*.*(..))")// 声明一个切点 方法名就是切点名
@Pointcut(value = "execution(* com.qfedu.dao.*.*.*(..))")
public void myPoint(){
}
@Before(value = "myPoint()") // 1.声明当前方法 是前置通知 2.和切点绑定
public void myBefore(JoinPoint joinPoint){
// joinPoint.getSignature().getName() 获取方法名
System.out.println("前置通知:"+joinPoint.getSignature().getName());
}
/**
* 环绕通知 :决定目标对象是否执行 拦截发生在 环绕不调用joinPoint.proceed(); 就是拦截
* @param joinPoint
*/
@Around(value = "myPoint()")
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知---前:"+joinPoint.getSignature().getName());
// Object result = null;
// 调用 目标对象执行相应的方法
Object result = joinPoint.proceed();
System.out.println("环绕通知---result"+result);
System.out.println("环绕通知---后"+joinPoint.getSignature().getName());
return result;
}
/**
* 后置通知 : 可以获取目标执行的结果 ,如果发生异常 不调用
* @param joinPoint
*/
@AfterReturning(pointcut = "myPoint()",returning = "result")
public void myAfterReturning(JoinPoint joinPoint,Object result){
System.out.println("后置通知:"+joinPoint.getSignature().getName());
System.out.println("后置通知--result:"+result);
}
/**
* 最终通知 无论方法 是否异常 都会通知
* @param joinPoint
*/
@After("myPoint()")
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知:"+joinPoint.getSignature().getName());
}
/**
* 异常通知 :不发生异常不调用
*
* Throwable e 接收异常信息
* @param joinPoint
*/
@AfterThrowing(pointcut = "myPoint()",throwing = "e")
public void myThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("异常通知"+joinPoint.getSignature().getName());
System.out.println("异常通知--异常信息:"+e.getMessage());
}
}
2、在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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
使用包扫描器 让注解生效 @Repository @Component @Service @Controller ....
-->
<context:component-scan base-package="com.qfedu"></context:component-scan>
<!--
激活 @Aspect
-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
3、测试
public class AspectAnnotationTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean_aspectj_annotation.xml");
// 只能获取接口 因为从容器获取的代理对象 是接口
IStudentDao studentDao = applicationContext.getBean(IStudentDao.class);
System.out.println("student:"+studentDao.findStudentById(2000));
}
}
以上是关于Spring的主要内容,如果未能解决你的问题,请参考以下文章
Spring boot:thymeleaf 没有正确渲染片段
What's the difference between @Component, @Repository & @Service annotations in Spring?(代码片段
spring练习,在Eclipse搭建的Spring开发环境中,使用set注入方式,实现对象的依赖关系,通过ClassPathXmlApplicationContext实体类获取Bean对象(代码片段
Spring Rest 文档。片段生成时 UTF-8 中间字节无效 [重复]
解决spring-boot启动中碰到的问题:Cannot determine embedded database driver class for database type NONE(转)(代码片段