JAVA AOP

本文介绍了面向切面编程(AOP)的基本概念和技术实现,包括使用JDK Proxy、CGLIB及Spring AOP的不同方式来实现业务逻辑的解耦。探讨了AOP的主要应用场景,并详细展示了如何利用Spring框架通过注解和配置文件方式来实现AOP。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 指定参数名称,以逗号分隔的参数名称列表。
### Java AOP (Aspect-Oriented Programming) Implementation and Usage In software engineering, Aspect-Oriented Programming (AOP) complements Object-Oriented Programming by facilitating the modularization of cross-cutting concerns such as logging, transaction management, security checks, etc., which span multiple classes or methods. In the context of Java applications, especially those built on top of frameworks like Spring, AOP plays an essential role in enhancing code maintainability and separation of concerns. #### Understanding Cross-Cutting Concerns Cross-cutting concerns refer to functionalities that affect more than one point of an application but do not fit well into any specific business logic component because they cut across various parts of the system. Traditional object-oriented programming languages struggle with encapsulating these concerns effectively without causing tight coupling between unrelated components[^2]. #### Implementing AOP Using Spring Framework The Spring framework supports two primary approaches for implementing AOP: - **Proxy-Based Approach**: Utilizes dynamic proxies or CGLIB libraries depending upon whether interfaces exist for advised objects. This approach works at runtime and is simpler to configure; however, it has limitations when dealing with constructor interceptions or private/protected members. - **AspectJ Weaving Approach**: Offers greater flexibility compared to proxy-based solutions since this technique allows intercepting method executions along with constructors inside target classes. However, using AspectJ requires understanding its weaving mechanism prior to adoption due to differences in operational modes[^1]. For developers preferring ease-of-use alongside powerful features offered out-of-the-box, Spring Boot simplifies configuring aspects via annotations while adhering closely to established conventions regarding singleton scopes unless explicitly overridden. Below demonstrates how simple it becomes under Spring Boot environment leveraging `@Aspect` annotation together with other utility annotations provided specifically for defining advice around join points. ```java import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void logMethodCall() { System.out.println("Logging Method Call"); } } ``` This example defines a basic aspect named `LoggingAspect`, where every time a service layer method from package `com.example.service` gets invoked, console output will display "Logging Method Call". Such implementations help decouple core functionality from supporting utilities ensuring cleaner architecture design principles throughout projects utilizing Java platforms.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值