`

Spring aop 基于schema的AOP支持及JoinPoint的使用、如何使用CGLIB代理

阅读更多

 基于schema的aop只是将配置写到配置文件中。

代码:

package com.lwf.aop;

public interface UserManager {

	public void add(String name, String password);
	public void del(String id);
	public void modify(int id ,String name, String password);
}

 

package com.lwf.aop;

public class UserManagerImpl implements UserManager {

	public void add(String name, String password) {

		System.out.println("add method");
	}

	public void del(String id) {
		System.out.println("del method");
	}

	public void modify(int id, String name, String password) {
		System.out.println("modify method");
	}

}

 

package com.lwf.aop;

public interface MySecurityManager {

	public void checkSecurity();
}

 

package com.lwf.aop;

public class MySecurityManagerImpl implements MySecurityManager {
	public void checkSecurity() {
		System.out.println("User security Check");
	}

}

 

注意上面的实现类中没有做任何@AspectJ的声明。

配置文件:

<?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:tx="http://www.springframework.org/schema/tx"
		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
			http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
		
>
	
	<bean id="userManager" class="com.lwf.aop.UserManagerImpl"></bean>
	<bean id="mySecurityManager" class="com.lwf.aop.MySecurityManagerImpl"></bean>
	<aop:config>
		<aop:aspect id="mySecurity" ref="mySecurityManager">
			<aop:pointcut expression="execution(* add*(..)) || execution(* del*(..))" id="allAddMethod" />
			<aop:before method="checkSecurity" pointcut-ref="allAddMethod"/>
		</aop:aspect>
	</aop:config>
</beans>

 

测试类:

package com.lwf.aop;

import junit.framework.TestCase;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Client extends TestCase{

	public void testAop(){
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserManager userManager = (UserManager)ac.getBean("userManager");
		userManager.add("zhangshang", "123456");
		userManager.del("23");
	}
}

 结果:

 

User security Check
add method
User security Check
del method

 注意我们配置文件中删除了:<aop:aspectj-autoproxy/>

 

JoinPoint的使用

在上面的checkSecurity方法中,我们没办法得到横切对象方法如add方法的参数。我们使用JoinPoint来解决。

上面示例只需要修改对应的checkSecurity方法即可。如我们修改MySecurityManagerImpl如下:

package com.lwf.aop;

import org.aspectj.lang.JoinPoint;

public class MySecurityManagerImpl implements MySecurityManager {
	public void checkSecurity(JoinPoint joinPoint) {
		 Object args[] = joinPoint.getArgs();
		 if(args!=null){
			for (int i = 0; i < args.length; i++) {
				System.out.println("args[" +i+"] =" + args[i]);
			}
		 }
		System.out.println("User security Check");
	}

}

 

我们通过给checkSecurity方法增加JoinPoint joinPoint参数,再通过getArgs方法得到add方法的参数。

现在测试Client.java

 

package com.lwf.aop;

import junit.framework.TestCase;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Client extends TestCase{

	public void testAop(){
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserManager userManager = (UserManager)ac.getBean("userManager");
		userManager.add("zhangshang", "123456");
		//userManager.del("23");
	}
}

 

输出如下:

args[0] =zhangshang
args[1] =123456
User security Check
add method

 

我们看到获取了用户名和密码。这种方法在不修改配置文件的条件下即可获得add方法参数。

 

需要注意的是因为spring aop默认采用的是J2SE实现的动态代理机制,而动态代理机制只能对接口代理,所以上面的代码UserManager必须是接口。如果不使用接口则要使用cglib代理,因为cglib代理可以对类实现代理

如何使用cglib代理?

我们可以强制让spring aop使用cglib代理而不是jdk的动态代理。

只要在配置文件中将

<aop:config proxy-target-class="true">

 并且增加cglib库到我们的用户自定义库中。

下面来测试:

我们首先删除UserManager接口,也删除MySecurityManager接口(这个接口本来就可以不要)。

修改Client的测试代码。剩下的代码如下所示。

注意我们先不使用cglib测试:

package com.lwf.aop;

public class UserManagerImpl {

	public void add(String name, String password) {

		System.out.println("add method");
	}

	public void del(String id) {
		System.out.println("del method");
	}

	public void modify(int id, String name, String password) {
		System.out.println("modify method");
	}

}

 

package com.lwf.aop;

import org.aspectj.lang.JoinPoint;

public class MySecurityManagerImpl  {
	public void checkSecurity(JoinPoint joinPoint) {
		 Object args[] = joinPoint.getArgs();
		 if(args!=null){
			for (int i = 0; i < args.length; i++) {
				System.out.println("args[" +i+"] =" + args[i]);
			}
		 }
		System.out.println("User security Check");
	}

}

 

package com.lwf.aop;

import junit.framework.TestCase;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Client extends TestCase{

	public void testAop(){
		ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		//UserManager userManager = (UserManager)ac.getBean("userManager");
		//userManager.add("zhangshang", "123456");
		//userManager.del("23");
		
		UserManagerImpl userManager = (UserManagerImpl)ac.getBean("userManager");
		userManager.add("zhangshang", "123456");
	}
}

 

<?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:tx="http://www.springframework.org/schema/tx"
		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
			http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
		
>
	
	<bean id="userManager" class="com.lwf.aop.UserManagerImpl"></bean>
	<bean id="mySecurityManager" class="com.lwf.aop.MySecurityManagerImpl"></bean>
	<aop:config >
		<aop:aspect id="mySecurity" ref="mySecurityManager">
			<aop:pointcut expression="execution(* add*(..)) || execution(* del*(..))" id="allAddMethod" />
			<aop:before method="checkSecurity" pointcut-ref="allAddMethod"/>
		</aop:aspect>
	</aop:config>
</beans>

 测试输出结果:

org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'userManager' defined in class path resource [applicationContext.xml]: 
Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: 
Cannot proxy target class because CGLIB2 is not available. Add CGLIB to the class path or specify proxy interfaces.	

 我们可以看到删除UserManager接口,而默认情况下使用JDK动态代理又需要该接口,所以报错,提示在这种情况下应该要使用cglib代理。

下面我们使用cglib代理,一加入cglib库,二修改配置文件如下:

<?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:tx="http://www.springframework.org/schema/tx"
		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
			http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
		
>
	
	<bean id="userManager" class="com.lwf.aop.UserManagerImpl"></bean>
	<bean id="mySecurityManager" class="com.lwf.aop.MySecurityManagerImpl"></bean>
	<aop:config proxy-target-class="true">
		<aop:aspect id="mySecurity" ref="mySecurityManager">
			<aop:pointcut expression="execution(* add*(..)) || execution(* del*(..))" id="allAddMethod" />
			<aop:before method="checkSecurity" pointcut-ref="allAddMethod"/>
		</aop:aspect>
	</aop:config>
</beans>

 

输出结果:

args[0] =zhangshang
args[1] =123456
User security Check
add method

 

通常我们使用JDK的动态代理就可以了,一般我们是对一些之前开发的系统,因为没有接口类,所以考虑使用cglib代理进行增加spring aop 的功能。

J2SE动态代理和CGLIB字节码生成代理的区别?
	* J2SE动态代理只针对接口进行代理,不能针对类
	* CGLIB是针对类实现代理,主要对指定的类生成一个子类,并覆盖其中的方法,从而实现方法的拦截,
	  因为是通过继承,所以无法为final方法提供代理

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics