静态代理案列:
第一步: 创建普通的类:
@Data
public class Student {
? ? private String name;
? ? private int age;
}
第二步:创建一个接口,这个接口可以对学生进行操作或不操作
public interface IStudentService {
? ? void save();
? ? Student query(Long id);
}
第三部:创建接口的实现类,这个实现就是要被代理的对象,也叫目标类,实现IStudentService接口
public class StudentServiceImpl implements IStudentService{
? ? @Override
? ? public void save() {
? ? ? ? System.out.println("保存一个学生");
? ? }
? ? @Override
? ? public Student query(Long id) {
? ? ? ? Student student=new Student();
? ? ? ? student.setName("张三");
? ? ? ? student.setAge(20);
? ? ? ? return student;
? ? }
}
第四步:创建增强类和增强方法,在目标对象方法运行的时候进行切入或者增强
public class DaoTranction {
? ? public void before(){
? ? ? ? System.out.println("开启事物之前");
? ? }
? ? public void after(){
? ? ? ? System.out.println("开始事物之后");
? ? }
}
第五步:创建静态代理对象:和目标类实现相同的接口,对外保持相同的服务
public class jingtaidailiduixiang? implements IStudentService{
? ? //指定目标对象
? ? private StudentServiceImpl studentService;
? ? //指定增强类
? ? private DaoTranction daoTranction;
? ? ////通过构造方法出入增强类和要拦截的对象
? ? public jingtaidailiduixiang(StudentServiceImpl studentService, DaoTranction daoTranction) {
? ? ? ? this.studentService = studentService;
? ? ? ? this.daoTranction = daoTranction;
? ? }
? ? @Override
? ? public void save() {
? ? ? ? daoTranction.before();
? ? ? studentService.save();
? ? ? daoTranction.after();
? ? }
? ? @Override
? ? public Student query(Long id) {
? ? ? ? return studentService.query(id);
? ? }
}
第六步:测试
public class test {
? ? public static void main(String[] args) {
? ? ? ? /*
? ? ? ? *? private StudentServiceImpl studentService;
? ? private DaoTranction daoTranction;
? ? * */
? ? ? ? ? //定义指定目标对象
? ? ? ? StudentServiceImpl studentService=new StudentServiceImpl();
? ? ? ? //定义增强类
? ? ? ? DaoTranction daoTranction=new DaoTranction();
? ? ? ? //定义代理对象,并指定该代理对象的目录对象和增强对象
? ? ? ? jingtaidailiduixiang jingtaidailiduixiang=new jingtaidailiduixiang(studentService,daoTranction);
? ? ? ? jingtaidailiduixiang.save();
? ? ? ? jingtaidailiduixiang.query(1L);
? ? }
}
总结:静态代理是的已经写死了目标对象,在编译的时候就确定我要代理哪个对象
动态代理案例:
第一步:定义一个普通类,可以在目标类或接口中操作这个类
@Data
public class Dog {
? ? private String naem;
? ? private int age;
}
第二步:定义接口:
public interface IDogservice {
? ? void save(Dog dog);
? ? Dog query(Long id);
}
第三部:定义接口的实现类,这个实现类会是要被代理的对象,即目标类
public class DogServiceImpl implements IDogservice{
? ? @Override
? ? public void save(Dog dog) {
? ? ? ? System.out.println("保存了一只"+dog);
? ? }
? ? @Override
? ? public Dog query(Long id) {
? ? ? ? Dog dog=new Dog();
? ? ? ? dog.setAge(20);
? ? ? ? dog.setNaem("大黄");
? ? ? ? return null;
? ? }
}
第四步:定义方法拦截器,在方法拦截器中可以指定拦截哪个类的哪个方法,对拦截到方法进行增强处理。这个拦截器必须实现InvocationHandler接口
public class TransactionHandler implements InvocationHandler {
? ? //指定增强方法
? ? private DaoTranction daoTranction;
? ? //指定要拦截的对象
? ? private Object Object;
//通过构造方法出入增强类和要拦截的对象
? ? public TransactionHandler(DaoTranction daoTranction, Object Object) {
? ? ? ? this.daoTranction = daoTranction;
? ? ? ? this.Object = Object;
? ? }
? ? //invoke方法,对要拦截的方法运行,并织入增强方法
? ? @Override
? ? public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
? ? ? ? ? Object ret=null;
? ? ? ? if(method.getName().equals("save")){
? ? ? ? ? ? daoTranction.before();
? ? ? ? ? ret= method.invoke(Object,objects);
? ? ? ? ? ? daoTranction.after();
? ? ? ? }else {
? ? ? ? ? ret=? method.invoke(Object,objects);
? ? ? ? }
? ? ? ? return ret;
? ? }
}
第五步:测试:
public class test {
? ? public static void main(String[] args) {
? ? ? ? //定义目标对象
? ? ? ? DogServiceImpl dogService=new DogServiceImpl();
? ? ? ? //定义增强类
? ? ? ? DaoTranction daoTranction=new DaoTranction();
? ? ? ? //定义方法拦截器,指定对哪个目标对象进行增强,并且指定增强类
? ? ? ? TransactionHandler transactionHandler=new TransactionHandler(daoTranction,dogService);
//? ? ? ? IDogservice proxy = (IDogservice) Proxy.newProxyInstance(DogServiceImpl.class.getClassLoader(), DogServiceImpl.class.getInterfaces(), transactionHandler);
//? ? ? ? proxy.save();
? ? ? ? IDogservice? o = (IDogservice) Proxy.newProxyInstance(test.class.getClassLoader(), DogServiceImpl.class.getInterfaces(), new InvocationHandler() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
? ? ? ? ? ? ? ? daoTranction.before();
? ? ? ? ? ? ? ? method.invoke(dogService, objects);
? ? ? ? ? ? ? ? return null;
? ? ? ? ? ? }
? ? ? ? });
//? ? ? IDogservice proxy= (IDogservice) Proxy.newProxyInstance(DogServiceImpl.class.getClassLoader(), DogServiceImpl.class.getInterfaces(), transactionHandler);
//? ? ? proxy.save();
//? ? ? ? ? ? Proxy.newProxyInstance(DogServiceImpl.class.getClassLoader(), DogServiceImpl.class.getInterfaces(), new InvocationHandler() {
//
//? ? ? ? ? ? ? ? @Override
//? ? ? ? ? ? ? ? public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//? ? ? ? ? ? ? ? ? ? return null;
//? ? ? ? ? ? ? ? }
//? ? ? ? ? ? });
//? ? ? ? ? ? Proxy.newProxyInstance(List.class.getClassLoader(), List.class.getInterfaces(), new InvocationHandler() {
//
//? ? ? ? ? ? ? ? @Override
//? ? ? ? ? ? ? ? public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
//? ? ? ? ? ? ? ? ? ? return null;
//? ? ? ? ? ? ? ? }
//? ? ? ? ? ? });
? ? }
}
总结:动态代理是可以指定任意的目标对象,Proxy.newProxyInstance方法可以方便的代理任意目标对象
注意:动态代理和静态代理的目标对象都要实现接口,并且代理代理也是实现了统一的接口
Cglib代理模式:
如果目标对象没有实现接口,我们将无法用静态代理或者动态代理生成代理对象,我们可以通过第三方框架Cglib,来生成目标对象的子类来生成代理对象实现对目标对象的增强
Cglib代理模式案列:
第一步:导入第三方依赖包:
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>cglib</groupId>
? ? ? ? ? ? <artifactId>cglib</artifactId>
? ? ? ? ? ? <version>2.2.2</version>
? ? ? ? </dependency>
第二步创建目标类:
public class StudentServiceImpl{
? ? @Override
? ? public void save(Student student) {
? ? ? ? System.out.println("保有学员信息");
? ? }
? ? @Override
? ? public Student query(Long id) {
? ? ? ? System.out.println("查询操作");
? ? ? ? Student student=new Student();
? ? ? ? student.setName("sy").setAge(20);
? ? ? ? return student;
? ? }
}
第三部:创建cglib拦截器,在拦截器中有个参数是目标类的子类,用子类调用父类的方法,可以在父类方法运行的时候对方法进行增强:
public class Cglibinterceptor implements MethodInterceptor {
? ? //指定增强
? ? private DaoTranaction daoTranaction;
? ? //增强通过构造传入
? ? public Cglibinterceptor(DaoTranaction daoTranaction) {
? ? ? ? this.daoTranaction = daoTranaction;
? ? }
? //参数methodProxy表示目标对象的父类,通过子类调用父类方法,在方法运行是调用增强类的方法对目标对象方法增强
? ? @Override
? ? public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
? ? ? ? daoTranaction.befor();
? ? ? ? Object ret=? methodProxy.invokeSuper(o,objects);
? ? ? ? daoTranaction.after();
? ? ? ? return ret;
? ? }
}
第四步:测试:
public class test {
? ? public static void main(String[] args) {
? ? ? ? //创建一个cglib拦截器,并指定增强类
? ? ? ? Cglibinterceptor cglibinterceptor = new Cglibinterceptor(new DaoTranaction());
? ? ? ? //使用Cglib框架给我们提交了一个Enhancer,用这个类设置父类和拦截器,并创建子类
? ? ? ? Enhancer enhancer = new Enhancer();
? ? ? ? enhancer.setSuperclass(StudentServiceImpl.class);
? ? ? ? enhancer.setCallback(cglibinterceptor);
? ? ? ? IStudentservice iStudentservice? = (IStudentservice) enhancer.create();
? ? ? ? iStudentservice.save(new Student());
? ? }
}
语法上:
① JDK动态代理需要目标类有父接口
② JDK动态代理产生的代理对象是目标类的兄弟
③ CGLIB动态代理不需要父接口,但是目标类不能被final修饰
④ CGLIB动态代理产生的代理对象是目标类的子类
性能上:
① JDK产生代理对象的性能较高;CGLIB较低
② JDK动态代理调用方法的性能较低;CGLIB较高
③ 两者的适用场合不同:
JDK动态代理适合于频繁创建的场景;
如果是单例或对象池的场景(无需频繁创建代理对象),但需要频繁调用代理方法,优先考虑CGLIB动态代理。