Spring学习-IOC与AOP

IOC:spring核心功能之一 控制反转

主要通过 注解+反射+工厂;

写一个简易版本的IOC实现方式

定义实体类

public class User {

    private String userName;
    private Integer age;
    public User(String userName, Integer age) {
        this.userName = userName;
        this.age = age;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User [userName=" + userName + ", age=" + age + "]";
    }

}

定义注解@ConponentDiy  (标明是容器所管理的类 的功能)

@Target({ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME )
public @interface ComponentDiy {
/**
 *              @Target(ElementType.TYPE)   //接口、类、枚举、注解
 *              @Target(ElementType.FIELD) //字段、枚举的常量
 *              @Target(ElementType.METHOD) //方法
 *              @Target(ElementType.PARAMETER) //方法参数
 *         @Target(ElementType.CONSTRUCTOR)  //构造函数
 *              @Target(ElementType.LOCAL_VARIABLE)//局部变量
 *         @Target(ElementType.ANNOTATION_TYPE)//注解
 *         @Target(ElementType.PACKAGE) ///包  
 */

/**
 * @Retention:注解的保留位置         
 *       @Retention(RetentionPolicy.SOURCE)   //注解仅存在于源码中,在class字节码文件中不包含
 *       @Retention(RetentionPolicy.CLASS)     // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
 *       @Retention(RetentionPolicy.RUNTIME)  // 注解会在class字节码文件中存在,在运行时可以通过反射获取到

 */

/**
 *     @Document:说明该注解将被包含在javadoc中
 *
 *    @Inherited:说明子类可以继承父类中的该注解
 */

}

定义注解@InjectDiy  (自动注入功能) 

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectDiy {
}

 

演示 controller中通过注解自动注入Service对象

@ComponentDiy
public class UserController {
    @InjectDiy
    private UserService userService;

    public void getUser(){
        User usr = userService.getUsr();
        System.out.println(usr);
    }
}

定义Service

@ComponentDiy
public class UserService {
    public User getUsr(){
        User user = new User("张三",20);
        return user;
    }
}

 

核心实现功能点来了

public class IocContext {
    //用以存放容器所管理的Bean
    public static final Map<Class<?>,Object> applicationContext = new ConcurrentHashMap<Class<?>,Object>();

    static {
        //包扫描路径  相当于@ComponentScan配置的包扫描路径
        String packageName = "com.example.demo";
        try {
            initBean(packageName);
        }catch (Exception e){
            e.printStackTrace();

        }
    }

    private static void initBean(String packageName) throws Exception{
        Enumeration<URL> urls =
                Thread.currentThread().getContextClassLoader().
                        getResources(packageName.replaceAll("\\.","/"));
        while (urls.hasMoreElements()){
            //扫描加载指定包路径下的所有的Class,并判断该Class是否是@Component注解的类,
            //如果是,则创建实例,并保存到applicationContext缓存中。
            addClassByAnnotation(urls.nextElement().getPath(),packageName);
        }
        //IOC实现自动注入
        IocUtil.inject();
    }

    /**
     * 获取指定包下实现ComponnetDiy 的Bean实例
     * @param filePath
     * @param packageName
     */
    private static void addClassByAnnotation(String filePath,String packageName){
        try {
            File[] files = getClassFiles(filePath);
            if(files != null){
                for(File f : files){
                    String fileName = f.getName();
                    if(f.isFile()){
                        Class<?> clazz = Class.forName(packageName+"."+fileName.substring(0,fileName.lastIndexOf(".")));
                        //判断该类是否实现了注解
                        if(clazz.isAnnotationPresent(ComponentDiy.class)){
                            applicationContext.put(clazz,clazz.newInstance());
                        }
                    }else {
                        addClassByAnnotation(f.getPath(),packageName+"."+fileName);
                    }
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    public static File[] getClassFiles(String filePath){
        return new File(filePath).listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return file.isFile() && file.getName().endsWith(".class") || file.isDirectory();
            }
        });
    }

}

 

ICO工具类

public class IocUtil {

    public static void inject(){
        Map<Class<?>,Object> map = IocContext.applicationContext;
        try {
           for(Map.Entry<Class<?>,Object> entry : map.entrySet()){
               Class<?> clazz = entry.getKey();
               Object obj = entry.getValue();
               Field[] fields = clazz.getDeclaredFields();
               for(Field field : fields){
                   if(field.isAnnotationPresent(InjectDiy.class)){
                       Class<?> fieldClazz = field.getType();
                       field.setAccessible(true);
                       Object fieldObj = map.get(fieldClazz);
                       field.set(obj,fieldObj);
                   }
               }
           }
        }catch (Exception e){
            e.printStackTrace();
        }

    }
    
}

 

测试类:

public class Check {
    public static void main(String[] args) throws Exception {
        UserController userController = (UserController)IocContext.applicationContext.get(UserController.class);
        userController.getUser();
    }

}

打印结果如下:

 

Debugger解释一下

IOC示例代码参考:https://blog.csdn.net/jijianshuai/article/details/78708230

 

 

AOP实现方式

AOP好处和专业术语就不多扯了,不清楚的自行百度。

Spring的AOP实现主要有两种代理机制:

JDK动态代理:针对实现了接口的类产生代理

Cglib动态代理:针对没有实现接口的类产生代理,底层采用的字节码增强技术,生成被代理的类的子对象

 

先看一个例子

定义一个账户接口

public interface Count {
    //查询账户
    public void queryCount();
    //修改账户
    public void updateCount();
    
}

定义实现类

public class CountImpl implements Count {
    @Override
    public void queryCount() {
        System.out.println("开始查询账户.......");
    }

    @Override
    public void updateCount() {
        System.out.println("开始更新账户......");
    }
}

 

定义代理类

public class CountProxyStatic implements Count {

    private CountImpl countImpl;

    //覆盖构造器
    public CountProxyStatic(CountImpl countImpl){
        this.countImpl = countImpl; //其实就是要被增强的对象
    }

    @Override
    public void queryCount() {
        System.out.println("查询账户前置操作...");
        countImpl.queryCount();
        System.out.println("查询账户后置操作...");
    }

    @Override
    public void updateCount() {
        System.out.println("更新账户前置操作...");
        countImpl.updateCount();
        System.out.println("更新账户后置操作...");
    }
}

打印结果:

 

*    通过这种 静态代理 实现方法前置后置增强
*    静态代理缺陷很明显,一个代理类只能对一个业务接口的实现类进行增强。
*    如果有多个业务接口,那么定义多个实现类和代理类。
*    如果代理类对业务方法的增强都是一样的,那这样的话,在多个代理类中就会存在大量重复的代码。
*    这时候我们需要定义一个代理类,它能代理所有实现类的方法调用
*    根据传进来的业务实现类和方法名进行具体调用  这就是动态代理

 

下面开始介绍基于JDK实现的动态代理

定义接口(JDK实现的动态代理需要有接口)

public interface Subject {
    public void request();
}

定义接口实现类 

public class RealSubjuect implements Subject {
    @Override
    public void request() {
        System.out.println("来自真是客户的请求....");
    }
}

定义代理类(需要实现InvocationHandler接口)

public class DynamicSubject implements InvocationHandler {

    private Object obj; //其实就是被代理的对象

    public DynamicSubject(){

    }

    public DynamicSubject(Object obj){
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before ........");
        method.invoke(obj,args);
        System.out.println("after..........");
        return null;
    }
}

 

测试方法:

public class SubjuectTest {

    public static void main(String[] args) {
        Subject rs = new RealSubjuect();
        InvocationHandler ds = (InvocationHandler)new DynamicSubject(rs);
        //生成代理
        Subject subject = (Subject)Proxy.newProxyInstance(rs.getClass().getClassLoader(), rs.getClass().getInterfaces(), ds);
        //证明生成的代理对象是不是Proxy的实例
        System.out.println(subject instanceof Proxy);
        System.out.println("subject的classs是:"+subject.getClass().toString());
        System.out.print("subject中的属性有:");
        Field[] fields = subject.getClass().getDeclaredFields();
        for(Field f : fields){
            System.out.print(f.getName()+",");
        }
        System.out.print("\n"+"subject中的方法有:");
        Method[] methods = subject.getClass().getDeclaredMethods();
        for(Method method : methods){
            System.out.print(method.getName()+",");
        }
        System.out.println("\n" + "subject的父类是:" + subject.getClass().getSuperclass());
        System.out.print("\n" + "subject实现的接口是");
        Class<?>[] interfaces = subject.getClass().getInterfaces();
        for (Class i :interfaces){
            System.out.print(i.getName() + ",");
        }
        System.out.println("\n\n"+"运行结果为 :");
        subject.request();
    }
}

打印结果如下:

 

先看一个关键的方法:Proxy类中的newProxyInstance()方法

    //三个参数分别是:
    需要增强的对象的类加载器  需要增强的对象实现的所有接口  需要增强的对象的代理类 
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        //主要通过此方法生成$proxy0对象
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

 

主要通过这个getProxyClass0生成$proxy对象

 

 

 由此可见 通过Proxy类的newProxyInstance方法生成的是Proxy类型的对象$Proxy0(继承了Proxyl类,实现了被增强对象的接口),然后将此类强转成了Subject类。

当走到最后一步的时候

会自动跳转到代理类DynamicSubject的invoke方法中; 这一步又是怎么访问到的呢?

关键点就在于生成的代理类 $Proxy0类中

 

Proxy构造方法

class Proxy{  
    InvocationHandler h=null;  
    protected Proxy(InvocationHandler h) {  
        this.h = h;  
    }  
    ...  
}  

 

$Proxy类中的代码($Proxy是动态代理内存中生成的类)

public final class $Proxy0 extends Proxy implements Subject {  
    private static Method m1;  
    private static Method m0;  
    private static Method m3;  
    private static Method m2;  
  
    static {  
        try {  
            m1 = Class.forName("java.lang.Object").getMethod("equals",  
                    new Class[] { Class.forName("java.lang.Object") });  
  
            m0 = Class.forName("java.lang.Object").getMethod("hashCode",  
                    new Class[0]);  
  
            m3 = Class.forName("***.RealSubject").getMethod("request",  
                    new Class[0]);  
  
            m2 = Class.forName("java.lang.Object").getMethod("toString",  
                    new Class[0]);  
  
        } catch (NoSuchMethodException nosuchmethodexception) {  
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
        } catch (ClassNotFoundException classnotfoundexception) {  
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
        }  
    } //static  
  
    public $Proxy0(InvocationHandler invocationhandler) {  
        super(invocationhandler);   //在这里调用了上面的Proxy的构造方法
    }  
  
    @Override  
    public final boolean equals(Object obj) {  
        try {  
            return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final int hashCode() {  
        try {  
            return ((Integer) super.h.invoke(this, m0, null)).intValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    public final void request() {  
        try {  
            super.h.invoke(this, m3, null);  
            return;  
        } catch (Error e) {  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
  
    @Override  
    public final String toString() {  
        try {  
            return (String) super.h.invoke(this, m2, null);  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
}  

上述的h其实就是代理类DynamicSubject,

【        Subject rs = new RealSubjuect();
        InvocationHandler ds = (InvocationHandler)new DynamicSubject(rs);
        //生成代理
        Subject subject = (Subject)Proxy.newProxyInstance(rs.getClass().getClassLoader(), rs.getClass().getInterfaces(), ds);】

在生成代理对象$Proxy0的时候已经将代理类DynamicSubject(ds)当作参数传递过去了,在$Proxy0类中的构造方法中,调用了父类Proxy的构造方法。   

所以在最后一步调用request方法的时候 (subject == $Proxy 见上图)

其实就是代理对象$Proxy0 调用 request()方法的时候;

然后   super.h.invoke(this, m3, null);   

就是调用到了父类Proxy的Invoke方法;即:InvocationHandler.invoke();

JDK动态代理参考:https://paddy-w.iteye.com/blog/841798

 

 

Cglib实现动态代理

 

定义接口

public interface EatFacade {
    public void eat();
}

定义实现类

public class EatFacadeImpl implements EatFacade {
    @Override
    public void eat() {
        System.out.println("吃美食了...");
    }
}

定义增强类 

public class EatFacadeCglib implements MethodInterceptor {
    //其实就是业务对象类 供代理方法中进行真正的业务方法调用
    private Object target;

    public Object getInstance(Object target){
        this.target = target;  //给业务对象赋值
        Enhancer enhancer = new Enhancer(); //创建加强器 用于创建动态代理类
        enhancer.setSuperclass(this.target.getClass());  //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        //设置回调 对于代理类上所有方法调用 都会调用Callback,而Callback则需要实现intercept()方法进行拦截
        enhancer.setCallback(this);
        //创建动态代理对象并返回
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("吃饭前洗手准备....");
        methodProxy.invokeSuper(o,objects);
        System.out.println("吃饭后漱口....");
        return null;
    }
}

测试代码 

    public static void main(String[] args) {
        //动态代理cglib实现方式测试
        EatFacadeImpl eatFacadeimpl = new EatFacadeImpl();
        EatFacadeCglib cglib = new EatFacadeCglib();
        EatFacadeImpl eatFacadeCglib = (EatFacadeImpl) cglib.getInstance(eatFacadeimpl);
        eatFacadeCglib.eat();
    }

结果:

 

关于Cglib更加深入了解可以参考:https://www.cnblogs.com/chinajava/p/5880887.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值