标签:表达式 system cer 面向 throw 地方 代理类 private round
第一:什么是AOP?
AOP是面切面编程,是OOP的补充和增强,在程序开发中主要用来解决一些系统层面上的问题。比如,日志事物,权限等待。利用AOP可以对业务逻辑的各个部分进行分离,比如我们在做控制层的时候有时候会碰到需要一些验证等,而使用AOP可以将这些部分与业务逻辑分开,使我们的代码更加专注于业务逻辑的处理,这样不仅降低了逻辑部分之间的耦合性,还增强了代码的可重用性,同时也提高了开发的效率。
第二:AOP的原理是什么?
在我们学习AOP之前都碰到过这样一个问题,那就是我们设计一个项目的时候,往往这个项目的不同部分都是需要验证的,虽然我们可以把相同的代码复制到需要验证的地方,但是这样不仅增加了类之间的耦合性,还使得业务逻辑代码和验证代码混合在一起,不利于代码的维护和管理,而且还增加了大量的重复性代码。而AOP就可以很好的帮助我们解决这个问题,所谓的面向切面编程就是我们利用spring的IOC管理来告诉我们的业务逻辑代码需要插入一个验证信息了,这个时候就是利用AOP直接插入就可以了,而不需要我们在去关心需要什么样的代码这样的问题了。
当我们没有使用AOP的时候,我们就需要在每个需要验证的地方添加代码,而如果使用了AOP,我们只需要写一份代码,然后让IOC管理实现我们在需要的地方插入就可以了。
AOP是基于23种设计模式之一的代理模式来实现的,因为在学习AOP之前,我们需要来学习一下代理模式。
第三:代理模式
代理模式可以分为静态代理模式和动态代理模式;其中动态代理又可以分为jdk动态代理和cglib动态代理
先来学习静态代理:下面给出一个静态代理的小案例
静态代理需要有接口以及该接口的实现类
静态代理中需要用到的包:这里除了spring的IOC需要用到的包外还多了一个aop的包,需要注意
代码如下:
接口代码:
public interface SomeService {
String doSome();
void say();
}
接口的实现类代码:
public class SomeServiceImpl implements SomeService{
@Override
public String doSome() {
// TODO Auto-generated method stub
System.out.println("dosome");
return "halou..";
}
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("say....");
}
}
代理的实现方式之一:前置切面类:就是在调用该接口的实现类之前先执行该前置切面类的方法
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
// TODO Auto-generated method stub
System.out.println("前置通知》》》》");
}
}
测试类的代码:
public class Test1 {
public static void main(String[] args) {
// 获取ApplicationContext对象 加载配置文件 反射+xml解析
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
// 从容器中获取代理对象;这里不能直接获取目标对象,那样代理就失去了作用
SomeService service = ac.getBean("proxyFactoryBean", SomeService.class);
String res = service.doSome();
System.out.println(res);
System.out.println("-----------------");
service.say();
}
}
配置文件代码:
<?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:p="http://www.springframework.org/schema/p"
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 http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 注册目标对象 -->
<bean class="com.sxt.serviceimpl.SomeServiceImpl" id="someServiceImpl"/>
<!-- 注册前置通知 -->
<bean class="com.sxt.aspect.MyMethodBeforeAdvice" id="myMethodBeforeAdvice"/>
<!-- AOP 配置代理类 -->
<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean">
<!-- 配置代理类 -->
<property name="target" ref="someServiceImpl"/>
<!-- 配置代理类实现的接口 -->
<property name="interfaces" value="com.sxt.service.SomeService"/>
<!-- 配置通知 -->
<property name="interceptorNames">
<list>
<!-- 配置前置通知 -->
<value>myMethodBeforeAdvice</value>
</list>
</property>
</bean>
</beans>
这样方式较为复杂,之后会介绍使用注解的方式来实现AOP切面编程的。
测试结果如下:
动态代理之jdk代理模式:
接口代码:
public interface SomeService {
String doSome();
}
实现类代码:
public class SomeServiceImpl implements SomeService {
@Override
public String doSome() {
System.out.println("dosome....");
return "hello..";
}
}
测试类以及代理类代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.sxt.service.SomeService;
import com.sxt.serviceimpl.SomeServiceImpl;
/**
* @author ASUS 这是通过jdk动态代理的方式来测试
*
*/
public class Test {
public static void main(String[] args) {
//实例化目标对象
SomeService service=new SomeServiceImpl();
//通过jdk动态代理的方式获取代理对象
SomeService proxy=(SomeService) Proxy.newProxyInstance(service.getClass().getClassLoader(),//设置类加载器
service.getClass().getInterfaces(),//获取目标对象的所有实现的接口
new InvocationHandler() {
/**
* proxy 代理对象
* method 需要执行目标对象的方法
* args 目标对象的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法执行之前");
String invoke =(String)method.invoke(service, args);
System.out.println("方法执行之后");
return invoke.toUpperCase();
}
});
System.out.println(proxy.doSome());
}
}
运行结果如吓:
动态代理之cglib代理:在cglib代理中需要接口,只需要有对应的目标类就可以了。
目标类代码:
package com.sxt.serviceimpl;
/**
* @author ASUS
* cglib的目标类
*
*/
public class SomeServiceImpl {
public String doSome() {
System.out.println("dosome....");
return "hello..";
}
}
测试类代码:
import com.sxt.cglib.CglibProxy;
import com.sxt.serviceimpl.SomeServiceImpl;
/**
* @author ASUS 这是通过cglib动态代理的方式来测试
*
*/
public class Test {
public static void main(String[] args) {
//实例化目标对象
SomeServiceImpl service=new SomeServiceImpl();
//获取代理类
SomeServiceImpl proxy=new CglibProxy(service).createProxy();
System.out.println(proxy.doSome());
}
}
cglib代理类代码:
import java.lang.reflect.Method;
import com.sxt.serviceimpl.SomeServiceImpl;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* @author ASUS
* cglib代理类
*
*/
public class CglibProxy implements MethodInterceptor{
//目标对象
private SomeServiceImpl service;
public CglibProxy(SomeServiceImpl service) {
super();
this.service = service;
}
/**
* 创建代理对象
* @return
*/
public SomeServiceImpl createProxy() {
//获取Enhancer对象
Enhancer e=new Enhancer();
// 设置父类对象,设置目标对象的类型
e.setSuperclass(SomeServiceImpl.class);
//设置callback对象,就是this
e.setCallback(this);
return (SomeServiceImpl)e.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// TODO Auto-generated method stub
System.out.println("执行之前");
String invoke =(String) method.invoke(service, args);
System.out.println("执行之后");
return invoke.toUpperCase();
}
}
注意:在cglib代理中虽然不需要接口,但是要用到一个jar包
我们已经了解了代理模式的原理,现在我们来学习AOP的几种实现方式:
方式一:前置通知,顾名思义就是在目标类的方法执行执行,该前置类的方法会被执行
代码如下:
接口代码:
package com.sxt.service;
/**
* @author ASUS
* 静态代理的公共接口
*
*/
public interface SomeService {
String doSome();
void say();
}
接口的实现类代码:
import com.sxt.service.SomeService;
/**
* @author ASUS
* 前置代理接口的实现类
*
*/
public class SomeServiceImpl implements SomeService {
@Override
public String doSome() {
System.out.println("dosome....");
return "hello..";
}
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("ssssss");
}
}
前置代理类代码:
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
/**
* @author ASUS
*
*/
public class MyMethodBeforeAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
// TODO Auto-generated method stub
System.out.println("前置通知》》》");
}
}
测试类代码:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sxt.service.SomeService;
/**
* @author ASUS 测试类
*
*/
public class Test {
public static void main(String[] args) {
// 获取ApplicationContext对象 加载配置文件 反射+xml解析
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
// 从容器中获取代理对象
SomeService service = ac.getBean("proxyFactoryBean", SomeService.class);
String res = service.doSome();
System.out.println(res);
System.out.println("-----------------");
service.say();
}
}
配置文件代码:
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 注册目标对象 -->
<bean class="com.sxt.serviceimpl.SomeServiceImpl" id="someServiceImpl"/>
<!-- 注册前置通知 -->
<bean class="com.sxt.aspect.MyMethodBeforeAdvice" id="myMethodBeforeAdvice"/>
<!-- AOP 配置代理类 -->
<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean">
<!-- 配置代理类 -->
<property name="target" ref="someServiceImpl"/>
<!-- 配置代理类实现的接口 -->
<property name="interfaces" value="com.sxt.service.SomeService"/>
<!-- 配置通知 -->
<property name="interceptorNames">
<list>
<!-- 配置前置通知 -->
<value>myMethodBeforeAdvice</value>
</list>
</property>
</bean>
</beans>
测试结果如下:
需要用到的jar包如下:
AOP实现之后置通知:也就是在目标类的方法执行之后才会执行的
接口代码:
package com.sxt.service;
/**
* @author ASUS
* 静态代理的公共接口
*
*/
public interface SomeService {
String doSome();
void say();
}
实现类代码:
import com.sxt.service.SomeService;
/**
* @author ASUS
* 后置代理接口的实现类
*
*/
public class SomeServiceImpl implements SomeService {
@Override
public String doSome() {
System.out.println("dosome....");
return "hello..";
}
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("ssssss");
}
}
后置代理类的代码:
package com.sxt.aspect;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
/**
* @author ASUS
*
*/
public class MyAfterReturningAdvice implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
// TODO Auto-generated method stub
System.out.println("后置通知"+returnValue);
//returnValue=((String)returnValue).toUpperCase();
}
}
测试类代码:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sxt.service.SomeService;
/**
* @author ASUS 测试类
*
*/
public class Test {
public static void main(String[] args) {
// 获取ApplicationContext对象 加载配置文件 反射+xml解析
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
// 从容器中获取代理对象
SomeService service = ac.getBean("proxyFactoryBean", SomeService.class);
String res = service.doSome();
System.out.println(res);
System.out.println("-----------------");
service.say();
}
}
配置文件代码:
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 注册目标对象 -->
<bean class="com.sxt.serviceimpl.SomeServiceImpl" id="someServiceImpl"/>
<!-- 注册前置通知 -->
<!-- <bean class="com.sxt.aspect.MyMethodBeforeAdvice" id="myMethodBeforeAdvice"/> -->
<!-- 注册后置通知 -->
<bean class="com.sxt.aspect.MyAfterReturningAdvice" id="myAfterReturningAdvice"/>
<!-- AOP 配置代理类 -->
<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxyFactoryBean">
<!-- 配置代理类 -->
<property name="target" ref="someServiceImpl"/>
<!-- 配置代理类实现的接口 -->
<property name="interfaces" value="com.sxt.service.SomeService"/>
<!-- 配置通知 -->
<property name="interceptorNames">
<list>
<!-- 配置前置通知 -->
<!-- <value>myMethodBeforeAdvice</value> -->
<!-- 配置后置通知 -->
<value>myAfterReturningAdvice</value>
</list>
</property>
</bean>
</beans>
测试结果如下:
AOP实现之环绕代理通知:就是在整个目标类方法执行的前后都会执行该环绕代理类的方法
接口代码:
public interface SomeService {
String doSome();
void say();
}
实现类代码:
public class SomeServiceImpl implements SomeService {
@Override
public String doSome() {
System.out.println("dosome....");
return "hello..";
}
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("ssssss");
}
}
环绕代理通知代码:
测试类代码:
配置文件代码:
测试结果如下:
异常代理:
异常代理类代码:
接口代码:
实现类代码:
测试类代码:
配置文件代码参考上面的。这里需要自己随便创造一个异常。
由于在配置文件中配置代理类太麻烦了,下面我们来介绍使用注解的方式实现代理
利用注解的方式需要用到的jar包与上面的配置文件的方式不一样;这里需要用到一个aspectj-tools的jar包
这里一共要用到6个注解《比上面多了一个最终代理类》
注解一:@Aspect这个是用在代理类的前面的,与配置文件相结合
注解二:@Before这个是前置代理类的注解,用在前置代理方法的前面
注解三:@AfterReturning后置代理类的注解
注解四:@Around环绕注解
注解五:@AfterThrowing异常代理类注解
注解六:@After最终代理类注解
这里还要在注解的后面指明代理类方法切入的位置,前面的代理实现只能指明切入的类,不能指明具体的方法,而使用注解的方式则可以指明切入的具体的方法
因此,这个最为常用
代理类代码:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* @author ASUS
* @ASPECT表示该类就是一个切面
*
*/
@Aspect
public class MyAspect {
/**
* execution切入点表达式:定位该通知的切入点
* execution(* com.dpb.service.*.doSome(..))
*/
@Before("execution(* com.sxt.serviceimpl..*(..))")
public void before() {
System.out.println("前置通知");
}
/**
* 后置通知
*/
@AfterReturning(value="execution(* com.sxt.service.*.doSome(..))",returning="msg")
public void afterReturn(Object msg) {
System.out.println("后置通知"+msg);
}
/**
* 环绕通知
* @param pjp
* @return
* @throws Throwable
*/
@Around(value="execution(* com.sxt.service.*.doSome(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知之前");
String proceed =(String) pjp.proceed();
System.out.println("环绕通知之后"+proceed);
return proceed.toUpperCase();
}
/**
* 异常通知
* @param e
*/
@AfterThrowing(value="execution(* com.sxt.service.*.doSome(..)",throwing="e")
public void throwing(Exception e) {
System.out.println("异常通知"+e.getMessage());
}
/**
* 最终通知
*/
@After("execution(* com.sxt.service.*.doSome(..))")
public void after() {
System.out.println("最终通知---");
}
}
配置文件代码:在配置文件中需要指明目标对象,代理类对象以及开启aspectj注解
接口,实现类,测试类代码参照上面的代理通知类代码
在这里我们还介绍一种使用配置文件的实现方式
就是将前面分散的代理方式的代码的配置文件合在一起就可以了。
标签:表达式 system cer 面向 throw 地方 代理类 private round
原文地址:https://www.cnblogs.com/liyunfeng-deng/p/10274439.html