Spring AOP 概念
Spring AOP学习:
问题:
Spring IOC实现了对象之间依赖关系的解耦。如果开发过程中,需要更改对象,只需要
在配置文件中更改对象的配置路径即可完成对象的更换。但是,在保留原有对象的基础上
对原有功能代码进行功能扩展,是Spring IOC所不能实现的。
解决:
使用Spring AOP
特点:
在不改变原有对象的功能代码的基础上完成功能扩展。
概念:
面向切面的编程(扩展)。
术语:
前置通知:在原有功能执行之前扩充的代码。
后置通知:在原有功能执行之后扩充的代码。
切点:原有功能方法
织入:前置通知+切点+后置通知形成切面的过程
切面:前置通知+切点+后置通知形成的横向执行流程。
使用:
Schema-based方式
Aspectj方式
基于Aspectj的注解方式
流程:
导入jar包
配置配置文件
完成扩展
Schema-based方式
Schema-Based方式:
第一步:
导入jar包(Spring IOC包+AOP相关包)
第二步:
在src下创建applicationcontext.xml配置文件
加载Schema:
<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:myns="http://www.mycompany.com/schema/myns"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
配置相关bean
配置通知bean
配置切面
第三步:
创建通知类
前置通知:
创建一个实现了MethodBeforeAdvice接口的java类
实现接口方法before
参数:
Method arg0:切点方法对象
Object[] arg1:切点接收的实参数组
Object arg2:切点所在的对象
在配置文件中配置通知bean
在切面配置中配置关联
后置通知
创建一个实现了AfterReturningAdvice接口的java类
实现接口方法afterReturning
参数:
Object arg0:切点的返回值
Method arg0:切点方法对象
Object[] arg1:切点接收的实参数组
Object arg2:切点所在的对象
在配置文件中配置通知bean
在切面配置中配置关联
环绕通知
创建一个实现了MethodInterceptor接口的java类
实现接口方法invoke
参数:
MethodInvocation arg0:放行切点
在配置文件中配置通知bean
在切面配置中配置关联
注意:
在实现方法中需要对切点方法进行放行: Object obj=arg0.proceed();//放行,执行切点方法。
异常通知
创建一个实现了ThrowsAdvice接口的java类
实现接口方法afterThrowing
public void afterThrowing(Exception ex) throws Throwable {
System.out.println("我是异常通知");
}
Exception ex:接收的是切点的异常对象。
在配置文件中配置通知bean
在切面配置中配置关联
注意:
切点中的内部如果使用异常处理机制,则无法触发异常通通知。
通配符的作用:
1 <aop:pointcut expression="execution(* com.bjsxt.pojo.Car2.demo(..))" id="my"/><!--配置切点 -->
其中切点方式使用..表示参数个数个类型为任意,只要是方法名为demo的都会添加通知。
2 <aop:pointcut expression="execution(* com.bjsxt.pojo.Car2.*(..))" id="my"/><!--配置切点 -->
*是通配符,表示任意的方法名,类名,包名等。
第四步:
由Spring容器对象获取切点所在bean对象
调用切点方法完成功能操作。
-------------------------------------------------------------------------------------------------------
<?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:myns="http://www.mycompany.com/schema/myns"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 配置bean 没有使用Spring AOP -->
<bean id="car" class="com.bjsxt.pojo.Car"></bean>
<!--配置bean 使用Spring AOP-->
<!--Schema-Based方式 -->
<!--配置切点bean -->
<bean id="car2" class="com.bjsxt.pojo.Car2"></bean>
<!--配置前置通知bean -->
<bean id="before" class="com.bjsxt.advice.MyBefore"></bean>
<!--配置后置通知bean -->
<bean id="after" class="com.bjsxt.advice.MyAfter"></bean>
<!--配置环绕通知bean -->
<bean id="round" class="com.bjsxt.advice.MyRound"></bean>
<!--配置异常通知bean -->
<bean id="throw" class="com.bjsxt.advice.MyThrow"></bean>
<!--配置切面 -->
<aop:config>
<aop:pointcut expression="execution(* com.*.pojo.Car2.*(..))" id="my"/><!--配置切点 -->
<aop:advisor advice-ref="before" pointcut-ref="my"/><!--配置前置通知 -->
<aop:advisor advice-ref="after" pointcut-ref="my"/><!--配置后置通知 -->
<aop:advisor advice-ref="round" pointcut-ref="my"/><!-- 配置环绕通知 -->
<aop:advisor advice-ref="throw" pointcut-ref="my"/><!-- 配置异常通知 -->
</aop:config>
</beans>
基于AspectJ方式
AspectJ方式:
第一步:
导入jar包(Spring IOC+AOP包)
第二步:
在Src下创建applicationcontext.xml
加载Schema(IOC和AOP相关)
配置相关bean
第三步:
创建通知类
创建一个普通java类,创建四个方法。
前置通知方法
后置通知方法
环绕通知方法
public Object round(ProceedingJoinPoint p) throws Throwable{
System.out.println("AspectJ方式--环绕--前置");
Object obj=p.proceed();
System.out.println("AspectJ方式--环绕--后置");
return obj;
}
异常通知方法
在applicationcontext.xml中配置通知bean
<bean id="advice" class="com.bjsxt.adviceAs.Myadvice"></bean>
在applicationcontext.xml中配置切面
<aop:config>
<aop:aspect ref="advice">
<aop:pointcut expression="execution(* com.bjsxt.pojo.Car3.demo())" id="my1"/><!--配置切点 -->
<aop:before method="before" pointcut-ref="my1"/><!--前置通知 -->
<aop:after-returning method="after" pointcut-ref="my1"/><!--后置通知 -->
<aop:around method="round" pointcut-ref="my1"/><!-- 环绕通知 -->
<aop:after-throwing method="myThrow" pointcut-ref="my1" throwing="e"/><!--异常通知 -->
</aop:aspect>
</aop:config>
第四步:
创建Spring容器对象
获取切点bean对象
调用切点方法
总结:
AspectJ配置方式的通知方法中要获取切点的参数,配置特别麻烦,切点不能通配。
如果不需要切点的参数则使用AspectJ方式
如果需要参数使用Schema-based方式
-------------------------------------------------------------------------
使用注解(基于AspectJ)
@Component 默认使用无参构造器
Spring默认使用JDK代理模式
基于Aspectj的注解配置AOP:
1 导入jar包
2 创建Spring配置文件并完成基础配置
加载Schema
配置数据源
配置工厂
配置扫描
3 Spring使用注解配置
在spring配置文件中增加context的先关Schema
<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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
在Spring配置文件中配置注解扫描:
<context:component-scan base-package="com.bjsxt.advice,com.bjsxt.pojo"></context:component-scan>
注意:必须在Spring配置文件中声明使用了注解的类的包路径
4 使用注解替换XML的配置
替换bean配置(通用)
@Component
在类名上直接使用此注解,表示bean创建,相当于在Spring中配置了该类的bean标签。
类名首字母小写即为bean 的ID
替换切面配置
替换切点声明
在切点方法上直接使用@Pointcut注解声明切点,示例如下:
@Pointcut("execution(* com.bjsxt.pojo.Demo.demo())")
public void demo(){
System.out.println("Demo.demo()");
}
替换通知方法的配置
在通知类的类名上还要使用@Aspect进行声明该类为通知类。
在类的通知方法上使用注解
前置通知:@Before("切点的全限定路径") 示例:
@Before("com.bjsxt.pojo.Demo.demo()")
public void myBefore(){
System.out.println("注解----前置通知");
}
后置通知
@After("com.bjsxt.pojo.Demo.demo()")
public void after(){
System.out.println("注解---后置通知");
}
环绕通知
@Around("com.bjsxt.pojo.Demo.demo()")
public Object round(ProceedingJoinPoint p) throws Throwable{
System.out.println("注解--环绕--前置");
Object obj=p.proceed();
System.out.println("注解--环绕--后置");
return obj;
}
异常通知
@AfterThrowing("com.bjsxt.pojo.Demo.demo()")
public void myThrow(){
System.out.println("注解---异常");
}
注意:
一定要将动态代理模式设置为cglib代理模式
<!--配置动态代理模式 -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
--------------------------------------------------------------------------------------------------------------------------------------------
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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!--配置注解扫描 -->
<context:component-scan base-package="com.bjsxt.advice,com.bjsxt.pojo"></context:component-scan>
<!--配置动态代理模式 -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>
切点Bean的配置:
package com.bjsxt.pojo;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
public class Demo {
@Pointcut("execution(* com.bjsxt.pojo.Demo.demo())")
public void demo(){
System.out.println("Demo.demo()");
}
}
通知Bean的配置和切面的配置
package com.bjsxt.advice;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MyAdvice {
@Before("com.bjsxt.pojo.Demo.demo()")
public void myBefore(){
System.out.println("注解----前置通知");
}
@After("com.bjsxt.pojo.Demo.demo()")
public void after(){
System.out.println("注解---后置通知");
}
@Around("com.bjsxt.pojo.Demo.demo()")
public Object round(ProceedingJoinPoint p) throws Throwable{
System.out.println("注解--环绕--前置");
Object obj=p.proceed();
System.out.println("注解--环绕--后置");
return obj;
}
@AfterThrowing("com.bjsxt.pojo.Demo.demo()")
public void myThrow(){
System.out.println("注解---异常");
}
}
小案例
需求:
导入包:
aopalliance.jar
asm-3.3.1.jar
aspectjweaver.jar
cglib-2.2.2.jar
commons-logging-1.1.1.jar
commons-logging-1.1.3.jar
javassist-3.17.1-GA.jar
log4j-1.2.17.jar
log4j-api-2.0-rc1.jar
log4j-core-2.0-rc1.jar
mybatis-3.2.7.jar
mybatis-spring-1.2.3.jar
mysql-connector-java-5.1.30.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
spring-aop-4.1.6.RELEASE.jar
spring-aspects-4.1.6.RELEASE.jar
spring-beans-4.1.6.RELEASE.jar
spring-context-4.1.6.RELEASE.jar
spring-core-4.1.6.RELEASE.jar
spring-expression-4.1.6.RELEASE.jar
spring-jdbc-4.1.6.RELEASE.jar
spring-tx-4.1.6.RELEASE.jar
spring-web-4.1.6.RELEASE.jar
数据库根据实体类去创建
相关代码:
Src:
com.bjsxt.advice:
MyAfter.java:
package com.bjsxt.advice;
import java.lang.reflect.Method;
import java.util.Date;
import org.apache.log4j.Logger;
import org.springframework.aop.AfterReturningAdvice;
public class MyAfter implements AfterReturningAdvice{
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
//创建日志对象
Logger logger=Logger.getLogger(MyBefore.class);
//校验
if(arg0!=null){
logger.debug(arg2[0]+"在"+new Date().toLocaleString()+"登陆成功");
}else{
logger.debug("查无此人:"+arg2[0]+":登陆失败");
}
}
}
MyBefore.java:
package com.bjsxt.advice;
import java.lang.reflect.Method;
import java.util.Date;
import org.apache.log4j.Logger;
import org.springframework.aop.MethodBeforeAdvice;
public class MyBefore implements MethodBeforeAdvice{
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
//创建日志对象
Logger logger=Logger.getLogger(MyBefore.class);
//输出日志
logger.debug(arg1[0]+"在"+new Date().toLocaleString()+"点进行了登陆请求");
}
}
com.bjsxt.mapper:
UserMapper.java:
package com.bjsxt.mapper;
import com.bjsxt.pojo.User;
public interface UserMapper {
//查询用户信息---登录功能
User selUser(String uname,String pwd);
}
UserMapper.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.UserMapper">
<!--根据用户名和密码查询用户信息 -->
<select id="selUser" resultType="com.bjsxt.pojo.User" >
select * from t_user where uname=#{0} and pwd=#{1}
</select>
</mapper>
com.bjsxt.pojo:
User.java:
package com.bjsxt.pojo;
public class User {
private int uid;
private String uname;
private String pwd;
private String uphone;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getUphone() {
return uphone;
}
public void setUphone(String uphone) {
this.uphone = uphone;
}
@Override
public String toString() {
return "User [uid=" + uid + ", uname=" + uname + ", pwd=" + pwd + ", uphone=" + uphone + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((pwd == null) ? 0 : pwd.hashCode());
result = prime * result + uid;
result = prime * result + ((uname == null) ? 0 : uname.hashCode());
result = prime * result + ((uphone == null) ? 0 : uphone.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (pwd == null) {
if (other.pwd != null)
return false;
} else if (!pwd.equals(other.pwd))
return false;
if (uid != other.uid)
return false;
if (uname == null) {
if (other.uname != null)
return false;
} else if (!uname.equals(other.uname))
return false;
if (uphone == null) {
if (other.uphone != null)
return false;
} else if (!uphone.equals(other.uphone))
return false;
return true;
}
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(int uid, String uname, String pwd, String uphone) {
super();
this.uid = uid;
this.uname = uname;
this.pwd = pwd;
this.uphone = uphone;
}
}
com.bjsxt.service:
UserService.java:
package com.bjsxt.service;
import com.bjsxt.pojo.User;
public interface UserService {
/**
* 查询用户信息
* @param uname 用户名
* @param pwd 密码
* @return 返回存储了用户信息的User对象
*/
User selUserService(String uname,String pwd);
}
com.bjsxt.serviceImpl:
UserServiceImpl.java:
package com.bjsxt.serviceImpl;
import com.bjsxt.mapper.UserMapper;
import com.bjsxt.pojo.User;
import com.bjsxt.service.UserService;
public class UserServiceImpl implements UserService {
// 声明mapper接口属性
private UserMapper um;
public UserMapper getUm() {
return um;
}
public void setUm(UserMapper um) {
this.um = um;
}
//查询用户信息---登录功能
@Override
public User selUserService(String uname, String pwd) {
return um.selUser(uname, pwd);
}
}
com.bjsxt.servlet:
UserServlet.java:
package com.bjsxt.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.bjsxt.pojo.User;
import com.bjsxt.service.UserService;
/**
* Servlet implementation class UserServlet
*/
@WebServlet("/us")
public class UserServlet extends HttpServlet {
//声明业务层对象
private UserService us;
//初始化
@Override
public void init() throws ServletException {
//获取Spring容器对象
ApplicationContext ac=WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
//给业务层对象赋值
us=(UserService) ac.getBean("us");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求编码格式
req.setCharacterEncoding("utf-8");
//设置响应编码格式
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//获取请求信息
String uname=req.getParameter("uname");
String pwd=req.getParameter("pwd");
//处理请求信息
//获取业务层对象
User u=us.selUserService(uname, pwd);
//响应处理结果
if(u!=null){
resp.sendRedirect("main.jsp");
}else{
req.getRequestDispatcher("login.jsp").forward(req, resp);
}
}
}
applicationcontext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property>
<property name="username" value="root"></property>
<property name="password" value="1234"></property>
</bean>
<!-- 配置工厂-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置mapper扫描 -->
<bean id="mapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.bjsxt.mapper"></property>
<property name="sqlSessionFactory" ref="factory"></property>
</bean>
<!--配置其他bean -->
<!--配置业务bean -->
<bean id="us" class="com.bjsxt.serviceImpl.UserServiceImpl">
<property name="um" ref="userMapper"></property>
</bean>
<!--配置通知bean -->
<bean id="before" class="com.bjsxt.advice.MyBefore"></bean>
<bean id="after" class="com.bjsxt.advice.MyAfter"></bean>
<!--配置切面 -->
<aop:config>
<aop:pointcut expression="execution(* com.bjsxt.serviceImpl.UserServiceImpl.selUserService(..))" id="my"/>
<aop:advisor advice-ref="before" pointcut-ref="my"/>
<aop:advisor advice-ref="after" pointcut-ref="my"/>
</aop:config>
</beans>
log4j.properties:
log4j.rootCategory=info
log4j.logger.com.bjsxt.mapper=debug, CONSOLE
log4j.logger.com.bjsxt.advice=debug, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=- %c-%d-%m%n
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=D:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=- %c-%d-%m%n
WebContent:
login.jsp:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
<form action="us" method="get">
用户名:<input type="text" name="uname" value=""/><br />
密码:<input type="password" name="pwd"/><br />
<input type="submit" value="提交" />
</form>
</body>
</html>
WEB-INF:
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<!--配置Spring配置文件路径 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationcontext.xml</param-value>
</context-param>
<!--配置监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
源码地址:
链接:https://pan.baidu.com/s/1n31EHGehJi8TqvImoJM2bw 密码:gl6b
代理模式
其他链接
https://blog.csdn.net/cckevincyh/article/details/54962920
https://blog.csdn.net/u013126379/article/details/52121096
代理设计模式:
静态代理设计模式:
真实类:要进行功能扩展的类
代理类:进行功能扩展的类
接口:真实类和代理类都要实现
代理流程:
代理类和真实类必须实现同一个接口
在代理类中调用真实类的方法,并完成功能扩展
修改调用方法为调用代理类
缺陷:
代理类又程序员自己编写。
优点:
扩展真实类的功能
让真实类的方法功能更加明确。
保护真实对象
动态代理设计模式:
特点:
动态生成代理对象。
JDK动态代理: 基于 接口
第一步:创建一个实现InvocationHandler接口的java类
并实现invoke方法
参数:
Object arg0:表示动态产生的代理对象
Method arg1:表示真实方法的Method对象
Object[] arg2:表示接收的实参
注意:
写的是功能扩展代码。
第二步:
使用Proxy对象动态创建代理对象:
Proxy.newProxyInstance(TestBoss.class.getClassLoader(),new Class[]{Gongneng.class},new TestJdk());
使用返回值调用接口方法完成业务处理即可
注意:
该方法返回的是代理对象。
特点:
动态的产生代理对象
基于接口的,代理对象和真实对象需要实现相同的接口
不用导入jar包
基于反射,效率低下
cglib动态代理 :基于继承
第一步:
创建一个实现了MethodInterceptor接口的java类
实现接口方法:
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
System.out.println("你预约了吗?");
arg1.invoke(new Boss(), arg2);
System.out.println("记录吃饭记录");
return null;
}
Object arg0, 代理对象
Method arg1, 真实方法对象
Object[] arg2, 参数
MethodProxy arg3 代理方法对象
第二步:动态获取代理对象
Enhancer en=new Enhancer();
en.setSuperclass(Boss.class);//声明要继承的实现类
en.setCallback(new TestCglib());
Boss b2=(Boss)en.create();
b2.eat();
第三步:使用代理对象完成功能处理
特点:
基于继承的,效率较高
需要导入jar包
小结
Spring Aop概念学习
Schema-based方式
基于AspectJ方式
使用注解(基于AspectJ)
小案例
代理模式