基于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方法提供代理