自定义注解与设计模式

1.1什么是注解?

Jdk1.5新增新技术,注解。很多框架为了简化代码,都会提供有些注解。可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。

注解 分为内置注解(元注解jdk自带的)和自定义注解(spring 框架定义的)

1.2 什么内置注解

 比如说:

(1) @SuppressWarnings   再程序前面加上可以在javac编译中去除警告
(2) @Deprecated   带有标记的包,方法,字段说明其过时
(3)@Overricle   打上这个标记说明该方法是将父类的方法重写

1.3 实现自定义注解

元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
1.@Target

@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

1. CONSTRUCTOR:用于描述构造器

2. FIELD:用于描述域

3. LOCAL_VARIABLE:用于描述局部变量

4. METHOD:用于描述方法

5. PACKAGE:用于描述包

6. PARAMETER:用于描述参数

7. TYPE:用于描述类、接口(包括注解类型) 或enum声明


2.@Retention(用于反射)

表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
3.代码如下

@Target(value={ElementType.METHOD,ElementType.TYPE})
@Retention(value=RetentionPolicy.RUNTIME)
public @interface AnnotationTest {
    String value() default "";
    int num() default 0;
}
class AnnotationDemo{
    @AnnotationTest(value="123",num=1)
   public void show(){
   }
}

1.4 实现ORM框架映射 :ORM框架实体类与表字段不一致,底层生成sql语句原理

自定义注解Table

@Target(value=ElementType.TYPE)
@Retention(value=RetentionPolicy.RUNTIME)
public @interface Table {
    String name();
}

自定义注解property

@Retention(RetentionPolicy.RUNTIME)
public @interface Property {
    String name();
    int len();
}
 

实体类User

@Table(name="sys_user")
public class User {
    @Property(name="sys_uid", len = 19)
    private Integer uid;
    @Property(name="sys_uname", len = 50)
    private String uname;
    public Integer getUid() {
        return uid;
    }
    public void setUid(Integer uid) {
        this.uid = uid;
    }
    public String getUname() {
        return uname;
    }
    public void setUname(String uname) {
        this.uname = uname;
    }
    static{
        System.out.println("静态代码块");
    }
    public User() {
       System.out.println("user的无餐方法");
    }
    @Override
    public String toString() {
        return "User [uid=" + uid + ", uname=" + uname + "]";
    }
    public User(Integer uid, String uname) {
        super();
        this.uid = uid;
        this.uname = uname;
    }
}

  //反射机制获取class类
        Class forName= Class.forName("com.test.annotation.User");
        //获取Table注解
        Table table=(Table) forName.getAnnotation(Table.class);
        //拿到Table注解类所定义的name属性名称
        System.out.println(table.name());
        StringBuffer sb=new StringBuffer();
        sb.append("select ");
       Field[] fields= forName.getDeclaredFields();
       for (int i = 0; i < fields.length; i++) {
           Property property=fields[i].getAnnotation(Property.class);
           sb.append(property.name());
           if(i==fields.length-1){
               sb.append(" from");
           }else{
               sb.append(" , ");
           }
         }
       sb.append(table.name());
       System.out.println(sb);

输出答案

sys_user
select sys_uid , sys_uname fromsys_user

2.1 什么是设计模式?

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。

 

2.2 设计模式的分类?

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

其实还有两类:并发型模式和线程池模式

2.3 设计模式的六大原则

1、开闭原则(Open Close Principle)

开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科

3、依赖倒转原则(Dependence Inversion Principle)

这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。

4、接口隔离原则(Interface Segregation Principle)

这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。

5、迪米特法则(最少知道原则)(Demeter Principle)

为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。

6、合成复用原则(Composite Reuse Principle)

原则是尽量使用合成/聚合的方式,而不是使用继承。

2.1.1什么是单例模式?

 单例保证一个对象JVM中只能有一个实例,常见单例 懒汉式、饿汉式

 什么是懒汉式,当你需要的时候才会被实例,节约内存,懒汉式是线程不安全的,需要手动加synchronized,效率低。

 什么是饿汉式,就是当class文件被加载的时候,初始化,天生线程安全。

/**
 * @author ecomsh
 *单例模式
 *懒汉式:当你需要的时候才会被实例,节约内存,懒汉式是线程不安全的,需要手动加synchronized,效率低
 */
class Singleton{
    private static Singleton  singleton;
    private  Singleton(){};
    public static Singleton getSingleton(){
        if(singleton==null){
            synchronized (Singleton.class) {
                singleton=new Singleton();
            }
        }
        return singleton;
    }
}
public class SingletonTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Singleton so1= Singleton.getSingleton();
        Singleton so2= Singleton.getSingleton();
        System.out.println(so1==so2);答案为true
    }
}

 

/**
 * @author ecomsh
 *单例模式
 *饿汉式:当class文件被加载时才会被实例,天生就安全的,效率高
 */
class Singleton1{
    private static Singleton1  singleton1=new Singleton1();
    private  Singleton1(){};
    
    public static Singleton1 getSingleton(){
        return singleton1;
    }
}
public class SingletonTest1 {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Singleton1 so1= Singleton1.getSingleton();
        Singleton1 so2= Singleton1.getSingleton();
        System.out.println(so1==so2);答案为true
    }
}
 

 

 2.4.1什么工厂模式?

实现创建者和调用者分离,就我理解其实就是Java中的多态,一种接口多种实现

代码实现如下:

接口Car

public interface Car {
    public void sale();
}

AoDi类

public class AoDi implements Car {
    @Override
    public void sale() {
        System.out.println("我要买奥迪");
    }

}
BMW类

public class Bmw implements Car {
    @Override
    public void sale() {
        System.out.println("我要买宝马");
    }

}

Carfactory实现类测试

public class CarFactory {
    public static Car saleCar(String carType){
        Car car=null;

//jdk1.7之后,可以用String来判断
        switch (carType) {
            case "奥迪":
                car=new AoDi();
                break;
            case "宝马":
                car=new Bmw();
                break;
            default:
                break;
        }
        return car;
    }
    
    public static void main(String[] args) {
        Car aodi=CarFactory.saleCar("奥迪");
        aodi.sale();
        Car bmw=CarFactory.saleCar("宝马");
        bmw.sale();
    }

打印:

我要买奥迪
我要买宝马
}

2.5.1什么是代理?

通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用处理,或调用后处理。既(AOP微实现)  ,AOP核心技术面向切面编程。

2.5.2代理分类

静态代理(静态定义代理类)

动态代理(动态生成代理类)

Jdk自带动态代理

Cglib 、javaassist(字节码操作库)

2.5.3 静态代理:需要自己去实现代理类

优点:可以做到隔离业务代码与非业务代码,关注代码的实现,提高代码的重用型

缺点:一个委托类对应于一个代理类,他们都实现同一个接口,并且需要为每一个需要委托的方法编写相应的代理方法,对于项目中需要大量用到代理模式的情况,静态代理会增加非常多的代码量

代码如下

/**
 * @author ecomsh
 *定义Log日志接口
 */
public interface Log {
    public void log();
}

/**
 * @author ecomsh
 *委托类继承Log日志接口
 */
public class AddLog implements Log{
    @Override
    public void log() {
        System.out.println("add打印日志");
    }

}
 

/**
 * @author ecomsh
 *代理类继承Log日志接口,需调用委托类的方法
 */
public class ProxyLog implements Log {
    private AddLog addlog;
    
    public ProxyLog(AddLog addlog) {
        this.addlog=addlog;
    }

    @Override
    public void log() {
        System.out.println("开始打印日志");
      addlog.log();
        System.out.println("打印日志结束");
    }

    public static void main(String[] args) {
    ProxyLog proxylog=    new ProxyLog(new AddLog());
    proxylog.log();
    }
}

打印结果:

开始打印日志
add打印日志
打印日志结束
 

2.5.4JDK动态代理 实现InvocationHandler(不需要生成代理类)

代码如下:

public class JdkProxy implements InvocationHandler {

    /**
     * proxy 表示目标对象
     * method 表示目标对象的方法
     * args 表示目标对象传参的值
     *
     */
    private AddLog addLog;
    public  JdkProxy(AddLog addlog){
        this.addLog=addlog;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("我要开始打印日志咯!!");
      Object invoke=    method.invoke(addLog, args);
      System.out.println("我要结束打印日志咯!!");
      return invoke;
    }
    public static void main(String[] args) {
        AddLog addlog=new AddLog();
        JdkProxy jdkproxy=   new JdkProxy(addlog);
        //jdk通过反射机制生成代理类
        Log log=(Log)   Proxy.newProxyInstance(addlog.getClass().getClassLoader(),             addlog.getClass().getInterfaces(), jdkproxy);
            log.log();
    }

}

打印如下:

我要开始打印日志咯!!
add打印日志
我要结束打印日志咯!!
 

2.5.5 CGLIB代理:实现MethodInterceptor 接口 ,他并不是jdk自带的需引用cglib-2.2.jar,asm-3.3.1.jar包

代码如下:

public class CglibProxy implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] arr, MethodProxy methodproxy) throws Throwable {
        System.out.println("cglib动态代理开始打印日志");
        Object invoke=    methodproxy.invokeSuper(obj, arr);
        System.out.println("cglib动态代理结束打印日志");
        return invoke;
    }
    public static void main(String[] args) {
        CglibProxy cglibproxy=new CglibProxy();
        //动态代理使用asm框架生成代理类
        Enhancer enhancer=   new Enhancer();
        //设置目标对象
        enhancer.setSuperclass(AddLog.class);
        enhancer.setCallback(cglibproxy);
        Log log= (Log) enhancer.create();
        log.log();
    }
}

打印结果:

cglib动态代理开始打印日志
add打印日志
cglib动态代理结束打印日志

 

2.5.7CGLIB与JDK动态代理区别

jdk动态代理是由Java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。

注:asm其实就是java字节码控制.

 

在jdk代码中可以看到,在生成代理类时,传递的是实现类所实现的接口 targetObject.getClass().getInterfaces(),所以JDK只能对于接口进行做代理。如果换成类的话,则会抛java.lang.ClassCastException异常。 

在Spring的源码中,可以看到很多生成代理类的代码。

 

动态代理的应用

AOP(Aspect-OrientedProgramming,面向切面编程),AOP包括切面(aspect)、通知(advice)、连接点(joinpoint),实现方式就是通过对目标对象的代理在连接点前后加入通知,完成统一的切面操作。

实现AOP的技术,主要分为两大类:

一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;

二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。

默认的策略是如果目标类是接口,则使用JDK动态代理技术,如果目标对象没有实现接口,则默认会采用CGLIB代理。

如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。

转载于:https://my.oschina.net/lsm97103/blog/1579764

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring是一个开源的Java应用框架,它提供了一种轻量级的、非侵入性的编程和配置模型,用于构建企业级应用程序。在Spring中,有多种设计模式被使用和支持。 其中,BeanFactory和FactoryBean是两个与Spring中的对象创建和管理相关的设计模式。 BeanFactory是一个工厂模式的实现,它负责创建和管理应用程序中的对象(bean)。它是Spring框架的核心容器,负责加载、实例化和管理各种bean。BeanFactory使用了简单工厂模式,通过配置文件或注解来创建和配置bean实例。 FactoryBean是一个创建型设计模式,它允许在创建对象时进行更多的自定义逻辑。FactoryBean接口定义了一种标准的方式来创建、配置和返回对象。通过实现FactoryBean接口,开发人员可以控制bean的实例化过程,并在需要时进行额外的操作。FactoryBean常用于创建一些复杂的bean,例如数据源、缓存等。 除了BeanFactory和FactoryBean,Spring还应用了许多其他的设计模式,例如: - 单例模式:Spring中的单例模式确保每个bean在应用程序中只有一个实例,以提高性能和资源利用率。 - 模板方法模式:Spring的很多扩展都采用了模板方法模式,通过定义一个模板方法并允许子类实现特定的行为来扩展功能。 - 回调模式:Spring中的回调模式用于将逻辑委托给外部组件处理,以实现解耦和灵活性。 总结起来,Spring框架应用了多种设计模式来提供灵活、可扩展和可维护的解决方案。这些设计模式的使用使得Spring成为一个强大的应用框架,并提供了丰富的功能和扩展性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [简说spring 的设计模式](https://blog.csdn.net/weixin_50999683/article/details/123471176)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [Spring 使用中的设计模式](https://blog.csdn.net/baihui2503/article/details/102355550)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值