JAVA AOP编程
简介
面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
主要应用场景
日志记录,性能统计,安全控制,事务处理,异常处理,PV、UV统计等等
JDKProxy
java动态代理
1.被代理类实现接口。
2.创建InvocationHandler接口实现。
3.使用Proxy.newProxyInstance()创建被代理对象。
public interface LoginService {
String debark(String name);
}
public class LoginImp implements LoginService{
public String debark(String name) {
System.out.println("----------登陆中----------");
return name;
}
}
public class LoginProxy implements InvocationHandler{
private Object target;
public LoginProxy(Object obj){
target = obj;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("----------"+method.getName()+"开始----------");
/*调用被代理类的方法,传入参数args,得到返回*/
Object object = method.invoke(target, args);
System.out.println("----------"+method.getName()+"结束----------");
return object;
}
public Object getProxy(){
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(), this);
}
}
public class TestMain {
public static void main(String[] args) {
LoginImp loginImp = new LoginImp();
LoginProxy loginProxy = new LoginProxy(loginImp);
LoginService loginService = (LoginService)loginProxy.getProxy();
String name = loginService.debark("李连杰");
System.out.println("登陆人:"+name);
}
}
/*保存生成代理类的字节码到硬盘上*/
public class ProxyGeneratorUtils {
public static void writeProxyClassToHardDisk(Class calss,String path) {
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11", calss.getInterfaces());
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
CGlib
AOP类库:运行时生成代理扩展。
1.引入cglib的jar包。
public class LoginCglibProxy implements MethodInterceptor{
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
System.out.println("----------"+arg1.getName()+"开始----------");
Object result = arg3.invokeSuper(arg0, arg2);
System.out.println("----------"+arg1.getName()+"结束----------");
return result;
}
public Object getProxy(Object target){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
enhancer.setClassLoader(target.getClass().getClassLoader());
return enhancer.create();
}
}
public static void main(String[] args) {
LoginCglibProxy loginCglibProxy = new LoginCglibProxy();
LoginImp loginService = new LoginImp();
LoginImp proxy = (LoginImp)loginCglibProxy.getProxy(loginService);
String name = proxy.debark("李连杰");
System.out.println("登陆人:"+name);
}
AspectJ (TM)
AOP框架:编译时增强目标类生成新类的方式,需要特殊的编译工具。
Spring可以识别AspectJ关于方面,切入点,增强处理的注解。根据这些注解生成AOP代理。
AspectJ AOP 声明有几个概念:
Aspect(切面) | Joint point和Advice |
Joint point (连接点) | Advice执行的时机。 |
Pointcut(切入点) | Advice执行的地点,可以通过表达式来进行匹配。 |
Advice(通知) | 具体的操作。 |
<!-- 启动@AspectJ支持 -->
<aop:aspectj-autoproxy/>
Spring
Spring使用JDKProxy和CGlib两种方式来生成代理对象,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。
1.导入Spring AOP相关jar包。
<dependencies>
<!-- Spring AOP 主要的jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<!-- Spring AOP 依赖的其他jar -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1</version>
</dependency>
</dependencies>
Spring 注解方式 实现AOP
public interface LoginService{
public String login(String name);
}
public class LoginImpl implements LoginService{
public String login(String name) {
System.out.println("-----------"+name+"登陆中-----------");
if ("李连杰".equals(name)) {
throw new Error();
}
return name;
}
}
@Aspect
public class LoginHelper {
/*@Pointcut 声明一个共享的切入点*/
@Pointcut("execution(* www.wwq.test.LoginImpl.*(..))")
public void login(){}
@Before("target(www.wwq.test.LoginService) && args(name)")
public void beforeLogin(String name){
System.out.println("-----------"+name+"开始登陆-----------");
}
@AfterThrowing("target(www.wwq.test.LoginService) && args(name)")
public void beforeThrowing(String name){
System.out.println("-----------"+name+"登陆异常-----------");
}
}
<?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-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:aspectj-autoproxy/>
<bean id="login" class="www.wwq.test.LoginImpl"></bean>
<bean id="loginHelper" class="www.wwq.test.LoginHelper"></bean>
</beans>
public class TestMain {
public static void main(String[] args) {
ApplicationContext appCtx = new ClassPathXmlApplicationContext("applicationContext.xml");
LoginService login = (LoginService)appCtx.getBean("login");
String name = login.login("李连杰");
System.out.println("登陆人"+name);
}
}
Spring 配置文件方式 实现AOP
1.删除LoginHelper中的注解。
2.修改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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="login" class="www.wwq.test.LoginImpl"></bean>
<bean id="loginHelper" class="www.wwq.test.LoginHelper"></bean>
<aop:config>
<aop:aspect id="loginAop" ref="loginHelper">
<aop:before method="beforeLogin" pointcut="target(www.wwq.test.LoginService) and args(name)"/>
<aop:after method="beforeThrowing" pointcut="target(www.wwq.test.LoginService) and args(name)"/>
</aop:aspect>
</aop:config>
</beans>
Spring AOP 注解
@Aspect 声明一个切面。
@Before 匹配方法执行之前。
@AfterReturning 匹配方法正常返回之后。
@AfterThrowing 匹配方法抛出异常之后。
@After 匹配方法执行之后(无论是否抛出异常)。
@Around
Spring AOP 切入点表达式
1. execution(public * *(..))
所有public方法。
2. execution(* set*(..))
所有以set开头的方法。
3. execution(* www.wwq.test.LoginService.*(..))
LoginService接口定义的方法
4. execution(* www.wwq.test.*.*(..))
test包下的所有方法
5. execution(* www.wwq.test..*.*(..))
test包下/包里的所有方法
6. within(www.wwq.test.*)
test包下的所有方法
7. within(www.wwq.test..*)
test包下/包里的所有方法
8. this(www.wwq.test.LoginService)
代理对象实现LoginService接口
9. target(www.wwq.test.LoginService)
目标对象实现LoginService接口
10. args(java.io.Serializable)
任何在运行时传递的参数有可序列化的。
11. @target(org.springframework.transaction.annotation.Transactional)
任何有@Transactional注解的连接点(对象)
12. @within(org.springframework.transaction.annotation.Transactional)
任何有@Transactional注解的连接点(对象)
13. @annotation(org.springframework.transaction.annotation.Transactional)
任何有@Transactional注解的连接点(方法)
14. @args(www.wwq.test.Parameter)
任何在运行时传递的参数类型有@Parameter注解的连接点
15. bean(tradeService)
任何Spring bean名为tradeService”的连接点
16. bean(*Service)
Spring bean名称匹配通配符表达式"*Service"
Spring AOP XML标签
<aop:config> AOP声明。
<aop:aspect id="" ref=""> 声明一个切面
<aop:pointcut id="" expression=""> 声明一个切入点(共享)
<aop:before pointcut-ref="" method=""/> 匹配方法执行之前
<aop:after-returning pointcut-ref="" method=""/> 匹配方法正常返回之后
<aop:after-throwing pointcut-ref="" method=""/> 匹配方法抛出异常之后
<aop:after pointcut-ref="" method=""/> 匹配方法执行之后(无论是否抛出异常)
<aop:around pointcut-ref="" method=""/>
expression 匹配表达式
pointcut-ref 匹配表达式
method 执行方法
throwing 指定异常名称
arg-names 指定参数名称,以逗号分隔的参数名称列表。