(1)创建一个名为chapter03的Web项目,导入Spring框架所需JAR包到项目的lib目录中,并发布到类路径下

pom.xml
XML
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>chapter03</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>chapter03 Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
</dependencies>
<build>
<finalName>chapter03</finalName>
</build>
</project>
(2)在src目录下,创建一个com.itheima.jdk包,在该包下创建接口UserDao,并在该接口中编写添加和删除的方法


UserDao.java
java
package com.itheima.jdk;
public interface UserDao {
public void addUser();
public void deleteUser();
}
(3)在com.itheima.jdk包中,创建UserDao接口的实现类UserDaoImpl,分别实现接口中的方法,并在每个方法中添加一条输出语句。本案例中会将实现类UserDaoImpl作为目标类,对其中的方法进行增强处理。

UserDaoImpl.java
java
package com.itheima.jdk;
public class UserDaoImpl implements UserDao {
public void addUser() {
System.out.println("添加用户");
}
public void deleteUser() {
System.out.println("删除用户");
}
}
(4)在src目录下,创建一个com.itheima.aspect包,并在该包下创建切面类MyAspect,在该类中定义一个模拟权限检查的方法和一个模拟记录日志的方法,这两个方法就表示切面中的通知。

MyAspect.java
java
package com.itheima.aspect;
public class MyAspect {
public void check_Permissions() {
System.out.println("模拟权限检查...");
}
public void log() {
System.out.println("模拟日志记录...");
}
}
(5)在com.itheima.jdk包下,创建代理类JdkProxy,该类需要实现InvocationHandler接口,并编写代理方法。在代理方法中,需要通过Proxy类实现动态代理。

JdkProxy.java
java
package com.itheima.jdk;
import com.itheima.aspect.MyAspect;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements InvocationHandler {
private UserDao userDao;
public Object createProxy(UserDao userDao) { // 创建代理方法
this.userDao = userDao;
ClassLoader classLoader = JdkProxy.class.getClassLoader(); //类加载器
Class[] clazz = userDao.getClass().getInterfaces(); //被代理对象的所有接口
return Proxy.newProxyInstance(classLoader, clazz, this); //使用代理类,进行增强,返回的是代理后的对象
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
//proxy:被代理后的对象
//method:将要被执行的方法
//args:执行方法时需要的参数
MyAspect myAspect = new MyAspect(); //声明切面
myAspect.check_Permissions(); //前增强
Object obj = method.invoke(userDao, args); //在目标类上调用方法
myAspect.log(); //后增强
return obj;
}
}
(6)在com.itheima.jdk包中,创建测试类JdkTest。在该类中的main()方法中创建代理对象和目标对象,然后从代理对象中获得对目标对象userDao增强后的对象,最后调用该对象中的添加和删除方法

JdkTest.java
java
package com.itheima.jdk;
public class JdkTest {
public static void main(String[] args) {
JdkProxy jdkProxy = new JdkProxy(); // 创建代理对象
UserDao userDao= new UserDaoImpl(); // 创建目标对象
UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao); //从代理对象获得增强的目标对象
userDao1.addUser();
userDao1.deleteUser();
}
}
执行程序后,控制台的输出结果如图

通过一个案例来演示CGLIB代理的实现过程,具体步骤如下。
(1)在src目录下,创建一个com.itheima.cglib包,在包中创建一个目标类UserDao, UserDao不需要实现任何接口,只需定义一个添加用户的方法和一个删除用户的方法,如文件3-6所示。

UserDao.java
java
package com.itheima.cglib;
public class UserDao { //目标类
public void addUser() {
System.out.println("添加用户");
}
public void deleteUser() {
System.out.println("删除用户");
}
}
(2)在com.itheima.cglib包中,创建代理类CglibProxy,该代理类需要实现MethodInterceptor接口,并实现接口中的intercept()方法。
CglibProxy.java
java
package com.itheima.cglib;
import com.itheima.aspect.MyAspect;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
public Object createProxy(Object target){
Enhancer enhancer = new Enhancer(); // 创建一个动态类对象,Enhancer 是 cglib 的核心类
enhancer.setSuperclass(target.getClass()); //确定需要增强的类,设置其父类
enhancer.setCallback(this); //设置回调
return enhancer.create(); //创建代理对象
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//proxy 根据指定父类生成的代理对象
//method 拦截的方法
//args 拦截方法的参数数组
//methodProxy 方法的代理对象,执行父类的方法
MyAspect myAspect = new MyAspect(); //创建切面类对象
myAspect.check_Permissions(); //前增强
Object obj = methodProxy.invokeSuper(proxy, args); //在目标类上调用方法
myAspect.log(); //后增强
return obj;
}
}
(3)在com.itheima.cglib包中,创建测试类CglibTest。在该类的main()方法中首先创建代理对象和目标对象,然后从代理对象中获得增强后的目标对象,最后调用对象的添加和删除方法。
CglibTest.java
java
package com.itheima.cglib;
public class CgibTest {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy(); //创建代理对象
UserDao userDao = new UserDao(); //创建目标对象
UserDao userDao1 = (UserDao)cglibProxy.createProxy(userDao); //获取增强后的目标对象
userDao1.addUser();
userDao1.deleteUser();
}
}
执行程序后,控制台的输出结果如图
直接运行会报错

pom.xml
XML
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>chapter03</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>chapter03 Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
</dependencies>
<build>
<finalName>chapter03</finalName>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.6.2</version>
<configuration>
<mainClass>com.itheima.cglib.CgibTest</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
java
cd /Users/主机名/Project/javaee/chapter03 && CP=$(cat classpath.txt) && java --add-opens java.base/java.lang=ALL-UNNAMED -cp "target/classes:$CP" com.itheima.cglib.CgibTest
在chapter03的终端窗口运行上述代码

对ProxyFactoryBean类有了初步的了解后,接下来通过一个典型的环绕通知案例,来演示Spring使用ProxyFactoryBean创建AOP代理的过程,具体步骤如下。
(1)在核心JAR包的基础上,再向chapter03项目的lib目录中导入AOP的JAR包spring-aop-4.3.6.RELEASE.jar和aopalliance-1.0.jar
修改 pom.xml
XML
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>chapter03</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>chapter03 Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!-- 添加AOP相关依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>
<finalName>chapter03</finalName>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.6.2</version>
<configuration>
<mainClass>com.itheima.cglib.CgibTest</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
(2)在src目录下,创建一个com.itheima.factorybean包,在该包中创建切面类MyAspect。由于实现环绕通知需要实现org.aopalliance.intercept. MethodInterceptor接口,所以MyAspect类需要实现该接口,并实现接口中的invoke()方法,来执行目标方法。

MyAspect.java
java
package com.itheima.factorybean;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class MyAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
check_Permissions();
Object obj = mi.proceed();
log();
return obj;
}
public void check_Permissions(){
System.out.println("模拟检查权限...");
}
public void log(){
System.out.println("模拟记录日志...");
}
}
(3)在com.itheima.factorybean包中,创建配置文件applicationContext.xml,并指定代理对象
在 maven 项目中,在 resources 下创建applicationContext.xml
applicationContext.xml
XML
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<!-- 目标类-->
<bean id="userDao" class="com.itheima.jdk.UserDaoImpl" />
<!--切面类-->
<bean id="myAspect" class="com.itheima.factorybean.MyAspect" />
<!--代理对象-->
<bean id="userDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.itheima.jdk.UserDao" /> <!--指定代理接口-->
<property name="target" ref="userDao" /> <!--指定目标对象-->
<property name="interceptorNames" value="myAspect" /><!--指定切面类-->
<property name="proxyTargetClass" value="true"/><!--指定代理方式-->
</bean>
</beans>
(4)在com.itheima.factorybean包中,创建测试类ProxyFactoryBeanTest,在类中通过Spring容器获取代理对象的实例,并执行目标方法。
ProxyFactoryBeanTest.java
java
package com.itheima.factorybean;
import com.itheima.jdk.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ProxyFactoryBeanTest {
public static void main(String args[]){
String xmlPath = "applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserDao userDao = (UserDao) applicationContext.getBean("userDaoProxy");
userDao.addUser();
userDao.deleteUser();
}
}
执行程序后,控制台的输出结果如图
java
cd /Users/主机名/Project/javaee/chapter03 && export CP=$(cat classpath.txt) && java --add-opens java.base/java.lang=ALL-UNNAMED -cp "target/classes:$CP" com.itheima.factorybean.ProxyFactoryBeanTest
终端运行以上代码




