spring框架总结(03)重点介绍(Spring框架的第二种核心掌握)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring框架总结(03)重点介绍(Spring框架的第二种核心掌握)相关的知识,希望对你有一定的参考价值。
1、Spring的AOP编程
什么是AOP? ----- 在软件行业AOP为Aspect Oriented Programming 也就是面向切面编程,使用AOP编程的好处就是:在不修改源代码的情况下,可以实现代码功能的增强
AOP的实现原理(掌握)
JDK的动态代理(注意JDK的动态代理只能对实现了接口的类产生代理)
/**
* Jdk的动态代理
* @author lilong
*/
public class JdkProxy implements InvocationHandler{
//要代理的对象
private CustomerDao customerDao;
public JdkProxy(CustomerDao customerDao){
this.customerDao = customerDao;
}
/**
* 生成代理对象的方法
* @return
*/
public CustomerDao createProxy(){
CustomerDao proxy = (CustomerDao) Proxy.newProxyInstance(customerDao.getClass().getClassLoader(), customerDao.getClass().getInterfaces(), this);
return proxy;
}
/**
* 增强的方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("权限校验...");
return method.invoke(customerDao, args);
}
}
编写测试代码:
@Test
public void test1(){
CustomerDao customerDao = new CustomerDaoImpl();
JdkProxy jdkProxy = new JdkProxy(customerDao);
CustomerDao proxy = jdkProxy.createProxy();
proxy.save();
}
第二种代理方式Cglib方式(了解或者欣赏)
注意的是:Cglib可以对没有实现接口的类产生代理,生成子类来实现功能的增强
public class CglibProxy implements MethodInterceptor{
//要代理的对象
private LinkManDao linkManDao;
public CglibProxy(LinkManDao linkManDao) {
this.linkManDao = linkManDao;
}
public LinkManDao createProxy(){
//创建Cglib核心类
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(linkManDao.getClass());
//设置回调
enhancer.setCallback(this);
//生成代理
LinkManDao proxy = (LinkManDao) enhancer.create();
return proxy;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("日志记录");
Object obj = methodProxy.invokeSuper(proxy, args);
return obj;
}
}
n 编写测试代码
@Test
public void test2(){
LinkManDao linkManDao = new LinkManDao();
CglibProxy cglibProxy = new CglibProxy(linkManDao);
LinkManDao proxy = cglibProxy.createProxy();
proxy.save();
}
2、Spring的AOP开发方式(xml方式)
其中相关术语的介绍
AOP开发所需要的jar介绍
n AOP联盟的jar包:com.springsource.org.aopalliance-1.0.0.jar
n Spring提供的AOP的jar包:spring-aop-4.2.4.RELEASE.jar
n AspectJ的jar包:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
n Spring整合AspectJ的jar包:spring-aspects-4.2.4.RELEASE.jar
编写接口和实现类
ProductDao接口:
public interface ProductDao {
/**
* 持久层:产品保存
*/
public void save();
}
ProductDaoImpl实现类:
public class ProductDaoImpl implements ProductDao {
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
}
配置相关类到Spring中
<?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"
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">
<bean id="productDao" class="cn.itcast.dao.impl.ProductDaoImpl"></bean>
</beans>
编写切面类
/**
* 自定义切面类
* @author kevin
*/
public class MyAspectXml {
public void checkPrivilege(){
System.out.println("权限校验...");
}
}
配置切面类
<?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"
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">
<bean id="productDao" class="cn.itcast.dao.impl.ProductDaoImpl"></bean>
<bean id="myAspectXml" class="cn.itcast.aspect.MyAspectXml"></bean>
</beans>
进行AOP配置
<?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">
<bean id="productDao" class="cn.itcast.dao.impl.ProductDaoImpl"></bean>
<bean id="myAspectXml" class="cn.itcast.aspect.MyAspectXml"></bean>
<!-- AOP配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
</beans>
编写测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestAOP {
@Autowired
private ProductDao productDao;
@Test
public void test1(){
productDao.save();
}
}
总结:对切入点表达式语法进行总结
语法:[修饰符] 返回类型 包名.类名.方法名(形式参数)
常见写法:
n execution(public * *(..)) 所有的public方法
n execution(* set(..)) 所有set开头的方法
n execution(* com.xyz.service.AccountService.*(..)) AccountService类中的所有方法
n execution(* com.xyz.service.*.*(..)) com.xyz.service包下所有的方法
n execution(* com.xyz.service..*.*(..)) com.xyz.service包及其子包下所有的方法
3、Spring中AOP的通知类型
1.1.1. 前置通知:在方法执行之前增强。可以获得切入点信息。
<!-- AOP配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<!-- 前置通知 -->
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
public class MyAspectXml {
public void checkPrivilege(JoinPoint point){
System.out.println("权限校验..." + point);
}
}
1.1.2. 后置通知:在方法执行完之后增强。可以获取返回值信息。
/**
* 自定义切面类
* @author kevin
*/
public class MyAspectXml {
public void checkPrivilege(JoinPoint point){
System.out.println("权限校验..." + point);
}
public void afterReturn(Object result){
System.out.println("后置通知:" + result);
}
}
public class ProductDaoImpl implements ProductDao {
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
}
<!-- AOP配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<!-- 前置通知 -->
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
<!-- 后置通知 -->
<aop:after-returning method="afterReturn" pointcut-ref="pointcut2" returning="result"/>
</aop:aspect>
</aop:config>
1.1.3. 环绕通知:在方法执行前后都进行增强。可以阻止方法的执行。
public class ProductDaoImpl implements ProductDao {
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
@Override
public void update() {
System.out.println("持久层:产品更新");
}
}
public class MyAspectXml {
public void checkPrivilege(JoinPoint point){
System.out.println("权限校验..." + point);
}
public void afterReturn(Object result){
System.out.println("后置通知:" + result);
}
public Object around(ProceedingJoinPoint joinpoint){
System.out.println("环绕前执行");
Object obj = null;
try {
obj = joinpoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕后执行");
return obj;
}
}
<!-- AOP配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))" id="pointcut3"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<!-- 前置通知 -->
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
<!-- 后置通知 -->
<aop:after-returning method="afterReturn" pointcut-ref="pointcut2" returning="result"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pointcut3"/>
</aop:aspect>
</aop:config>
1.1.4. 异常抛出通知:当发生异常之后增强,可以获取异常信息。
public class ProductDaoImpl implements ProductDao {
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
@Override
public void update() {
System.out.println("持久层:产品更新");
}
@Override
public void find() {
System.out.println("持久层:查询");
int i = 10/0;
}
}
public class MyAspectXml {
public void checkPrivilege(JoinPoint point){
System.out.println("权限校验..." + point);
}
public void afterReturn(Object result){
System.out.println("后置通知:" + result);
}
public Object around(ProceedingJoinPoint joinpoint){
System.out.println("环绕前执行");
Object obj = null;
try {
obj = joinpoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕后执行");
return obj;
}
public void afterThrowing(Exception ex){
System.out.println("抛出异常通知:" + ex.getMessage());
}
}
<!-- AOP配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))" id="pointcut3"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))" id="pointcut4"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<!-- 前置通知 -->
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
<!-- 后置通知 -->
<aop:after-returning method="afterReturn" pointcut-ref="pointcut2" returning="result"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pointcut3"/>
<!-- 抛出异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
</aop:aspect>
</aop:config>
1.1.5. 最终通知:不管是否有异常,都会执行的
public class MyAspectXml {
public void checkPrivilege(JoinPoint point){
System.out.println("权限校验..." + point);
}
public void afterReturn(Object result){
System.out.println("后置通知:" + result);
}
public Object around(ProceedingJoinPoint joinpoint){
System.out.println("环绕前执行");
Object obj = null;
try {
obj = joinpoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕后执行");
return obj;
}
public void afterThrowing(Exception ex){
System.out.println("抛出异常通知:" + ex.getMessage());
}
public void after(){
System.out.println("最终通知");
}
}
<!-- AOP配置 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))" id="pointcut1"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))" id="pointcut2"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))" id="pointcut3"/>
<aop:pointcut expression="execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))" id="pointcut4"/>
<!-- 配置切面 -->
<aop:aspect ref="myAspectXml">
<!-- 前置通知 -->
<aop:before method="checkPrivilege" pointcut-ref="pointcut1"/>
<!-- 后置通知 -->
<aop:after-returning method="afterReturn" pointcut-ref="pointcut2" returning="result"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pointcut3"/>
<!-- 抛出异常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
<!-- 最终通知 -->
<aop:after method="after" pointcut-ref="pointcut4"/>
</aop:aspect>
</aop:config>
注意:最终通知和后置通知的区别:最终通知,不管异常与否,都执行;而后置通知在异常时不执行。
4、Spring的AOP注解
4.1. 创建工程,引入jar包,创建核心配置文件
<?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"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="cn.itcast"></context:component-scan>
<!-- 开启自动代理注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
4.2. 创建接口和实现类
public interface ProductDao {
/**
* 持久层:产品保存
*/
public void save();
public int delete();
public void update();
public void find();
}
@Repository("productDao")
public class ProductDaoImpl implements ProductDao {
@Override
public void save() {
System.out.println("持久层:产品保存...");
}
public int delete(){
System.out.println("持久层:产品删除...");
return 100;
}
@Override
public void update() {
System.out.println("持久层:产品更新");
}
@Override
public void find() {
System.out.println("持久层:查询");
}
}
4.3. 编写切面类
@Component("myAspectAnnotation")
@Aspect
public class MyAspect {
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint joinPoint){
System.out.println("权限校验..." + joinPoint.toString());
}
}
提示:此处的切面类可以不取id.
5、Spring的AOP 中注解通知
5.1. 前置通知
/**
* 前置通知
* @param joinPoint
*/
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint joinPoint){
System.out.println("权限校验..." + joinPoint.toString());
}
5.2. 后置通知
@Aspect
public class MyAspect {
/**
* 前置通知
* @param joinPoint
*/
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint joinPoint){
System.out.println("权限校验..." + joinPoint.toString());
}
@AfterReturning(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))",returning="result")
public void afterReturning(Object result){
System.out.println("后置通知:" + result);
}
}
5.3. 环绕通知
@Around("execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))")
public Object after(ProceedingJoinPoint joinpoint) throws Throwable{
System.out.println("环绕通知前增强");
Object obj = joinpoint.proceed();
System.out.println("环绕通知后增强");
return obj;
}
5.4. 异常通知
@AfterThrowing(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))",throwing="ex")
public void afterThrowing(Exception ex){
System.out.println("抛出异常通知");
}
5.5. 最终通知
@After("execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))")
public void after(){
System.out.println("最终通知");
}
5.6. PointCut注解(了解)
作用:用于定义切入点表达式的一个注解。
@Component("myAspectAnnotation")
@Aspect
public class MyAspect {
/**
* 前置通知
* @param joinPoint
*/
@Before("execution(* cn.itcast.dao.impl.ProductDaoImpl.save(..))")
public void checkPrivilege(JoinPoint joinPoint){
System.out.println("权限校验..." + joinPoint.toString());
}
@AfterReturning(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.delete(..))",returning="result")
public void afterReturning(Object result){
System.out.println("后置通知:" + result);
}
@Around("execution(* cn.itcast.dao.impl.ProductDaoImpl.update(..))")
public Object aroung(ProceedingJoinPoint joinpoint) throws Throwable{
System.out.println("环绕通知前增强");
Object obj = joinpoint.proceed();
System.out.println("环绕通知后增强");
return obj;
}
// @AfterThrowing(value="execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))",throwing="ex")
@AfterThrowing(value="MyAspect.pointcut()",throwing="ex")
public void afterThrowing(Exception ex){
System.out.println("抛出异常通知");
}
// @After("execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))")
@After("MyAspect.pointcut()")
public void after(){
System.out.println("最终通知");
}
@Pointcut("execution(* cn.itcast.dao.impl.ProductDaoImpl.find(..))")
public void pointcut(){
}
}
以上是关于spring框架总结(03)重点介绍(Spring框架的第二种核心掌握)的主要内容,如果未能解决你的问题,请参考以下文章
基于Spring Boot和Spring Cloud实现微服务架构学习-Spring框架介绍