首页 > 编程语言 >Java设计模式和AOP编程

Java设计模式和AOP编程

时间:2024-08-08 21:26:11浏览次数:20  
标签:Java void System class AOP println 设计模式 public out

Java 六大设计原则;Java 23种设计模式(在此介绍三种设计模式)

Java设计模式

单例模式

应用场景:spring中bean的作用域用的就是单例模式

//基本的单例模式————懒汉式
public class student {

    //3.创建static修饰的成员变量
    private static student stu;
    //1.设计私有构造方法
    private student() {
    }
    //2.提供一个共有的方法
    public static synchronized student getInstance(){
        if (stu == null){
            stu = new student();
        }
        return stu;
    }
}

//基本的单例模式————饿汉式

public class student {
    //3.创建static修饰的成员变量
    private static student stu = new student();
    //1.设计私有构造方法
    private student() {
    }
    //2.提供一个共有的方法
    public static synchronized student getInstance(){
        return stu;
    }

}

/*
     饿汉式与懒汉式的不同是:创建对象的时间点不同
 */

//测试类
        student stu1 = student.getInstance();
        student stu2 = student.getInstance();
        System.out.println(stu1 == stu2);  

工厂模式

//工厂类
public class NoodleFactory {
    //定义静态常量的标识————规定下面条的类型
    public static final int NOODLE_BIA = 1;
    public static final int NOODLE_REGAN = 2;
    public static final int NOODLE_LANZHOU = 3;

    //创建不同类型的面条
    public static INoodles getNoodle(int type) {
        if (type == 1) {
            return new BiaBiaMianImp();
        }else if(type == 2){
            return new ReGanMianImp();
        }else if(type == 3){
            return new LanzhouLaMianImp();
        }
        return null;
    }
}

//测试类
public class Test01 {
    public static void main(String[] args) {
        //方式1
        NoodleFactory.getNoodle(2).noodleType();
        //方式2
        NoodleFactory.getNoodle(NoodleFactory.NOODLE_REGAN).noodleType();
    }
}

//自定义接口及实现类
public interface INoodles {
    public void noodleType();
}

public class BiaBiaMianImp implements INoodles{

    @Override
    public void noodleType() {
        System.out.println("----来一碗边个边个面---");
    }
}

public class LanzhouLaMianImp implements INoodles{
    @Override
    public void noodleType() {
        System.out.println("-----来一碗兰州拉面----");
    }
}

public class ReGanMianImp implements INoodles{

    @Override
    public void noodleType() {
        System.out.println("----来一碗武汉热干面----");
    }
}

代理模式

功能:中间隔离;方法增强

静态代理

  • 是由程序员创建或特定工具自动生成源代码,在对其编译。
  • 在程序员运行之前,代理类.class文件就已经被创建了。
//自定义接口
public interface IWomen {
    public void makeEyeWithMan();
}

//被代理对象
public class PanJinLianImp implements IWomen{

    @Override
    public void makeEyeWithMan() {
        System.out.println("给ximenqing抛媚眼");
    }
}

//代理
public class WangPoImp implements IWomen{
    //被代理对象
    IWomen obj;

    //构造方法给属性赋值
    public WangPoImp(IWomen obj) {
        this.obj = obj;
    }


    @Override
    public void makeEyeWithMan() {
        System.out.println("镇壶酒,搞点气氛");
        obj.makeEyeWithMan();
    }
}


//测试类
public class XiMenTest {
    public static void main(String[] args) {
        //1.创建被代理对象
        IWomen pan = new PanJinLianImp();
        //2.创建代理
        IWomen wang = new WangPoImp(pan);

        wang.makeEyeWithMan();
    }
}

动态代理

  • 在程序运行时通过反射机制动态创建的。
  • 动态代理分为: 基于接口的动态代理(jdk自带);基于子类的动态代理(第三方)

基于接口的动态代理(jdk自带)

//自定义接口
public interface ISinger {
    public void sing();
    public int dance(int num);
}

//被代理
public class JinXingImp implements ISinger{

    @Override
    public void sing() {
        System.out.println("----有点甜---");
    }

    @Override
    public int dance(int num) {
        System.out.println("---哈哈哈哈----");
        return 0;
    }
}

//jdk动态代理测试
public class Test01 {
    public static void main(String[] args) {

        //1.创建被代理对象
        final ISinger jin = new JinXingImp();
        //2.创建代理对象
        final ISinger daiLi = (ISinger) Proxy.newProxyInstance(jin.getClass().getClassLoader(), jin.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("------自我介绍-----");
                Object obj = method.invoke(jin, args);
                return obj;
            }
        });
        daiLi.sing();
        daiLi.dance(6);
    }
}

基于子类的动态代理(第三方)

//自定义接口
public interface ISinger {
    public void sing();
    public int dance(int num);

}

//实现接口的类
public class TengImp implements ISinger{
    @Override
    public void sing() {
        System.out.println("听了赵雷的成都去了成都,听了汪峰的北京去了北京,至今不敢听腾格尔的天堂");
    }

    @Override
    public int dance(int num) {
        System.out.println("学武术,跳舞");
        return 0;
    }
}


//cglib动态代理测试
public class Test02 {
    public static void main(String[] args) {

        //1.创建被代理对象
        final ISinger teng = new TengImp();
        //2.创建代理对象
        ISinger dai = (ISinger) Enhancer.create(teng.getClass(), teng.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {

                Object obj = method.invoke(teng,objects);

                return obj;
            }
        });
        dai.sing();
        dai.dance(6);

    }
}

用动态代理的优化转账业务的案例见资源

AOP(面向切面编程)

AOP概述

将那些与业务无关,却为业务模块所共同调用的逻辑(例如:事务管理、日志管理、控制权限等)封装抽取成一个可重用的模块,这个模块被命名为"切面(Aspect)",便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性

 Spring AOP 基于动态代理实现

  • 如果被代理的对象,已经实现某个接口,则 Spring AOP 会使用 JDK Proxy(反射),基于接口的方式,创建代理对象(JDK动态代理的核心是InvocationHandler接口和Proxy类);
  • 如果被代理的对象,没有实现某个接口,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(Cglib动态代理的核心是MethodInterceptor接口和Enhancer类)

AOP相关概念

AOP通知类型

AOP将抽取出来的共性功能称为通知;通知类型:以通知在上下文中的具体位置作为划分

前置通知(Before)

返回通知(After-returning)

异常通知(After-throwing)

后置通知(After)

环绕通知(Around)

AOP连接点(Join point)

AOP将所有的方法都视为连接点,不管是接口里面的抽象方法,还是实现类里面的重写方法,都是连接点

AOP切点(Pointcut)

AOP将可能被抽取共性功能的方法称为切入点。切入点是连接点的子集

AOP目标对象(Target)

就是挖掉功能的方法对应的类生的对象,这种对象是无法直接完成最终工作的

AOP织入(Weaving)

是将挖掉的功能回填的动态过程

AOP切面

切点+通知

SpringAOP+AspectJ实现步骤

1.添加依赖,aop与aspectj表达式的依赖

2.创建spring的主配置文件,bean内的命名空间要添加aop的

3.创建业务代码并编写日志记录代码(事务管理代码)

4.将业务层与日志记录层注入spring容器

5.<aop:config>--aop配置 aop:aspect--aop切面 aop:before--通知内容与通知类型

切点表达式配置语法

execution(修饰符 返回值 包名称.类名称.方法名称(参数列表))

eg: execution(public void com.apesource.service.ServiceImp.findAll())

  • 1.修饰符可以省略代表任意 execution(返回值 包名称.类名称.方法名称(参数列表))
  • 2.返回值可以使用“*”代表任意 execution(* 包名称.类名称.方法名称(参数列表))
  • 3.包名可以使用“*”代表任意名称 execution(* *.*.*.类名称.方法名称(参数列表))
  • 4.包名可以使用“..”代表任意个数 execution(* *...类名称.方法名称(参数列表))
  • 5.类名与方法名可以使用“*”代表任意 execution(* *...*.*(参数列表))
  • 6.参数列表可以使用".."代表任意个数任意类型 execution(* *...*.*(..))

注:如果有参数 int======>int; String===>java.lang.String

xml版的面向切面编程案例部分代码展示

//日志工具类
public class Logger {
    public void brforeLogger(){
        System.out.println("日志类logger中调用前置Logger方法进行日志记录");
    }
    public void returnLogger(){
        System.out.println("日志类logger中调用返回Logger方法进行日志记录");
    }
    public void throwLogger(){
        System.out.println("日志类logger中调用异常Logger方法进行日志记录");
    }
    public void afterLogger(){
        System.out.println("日志类logger中调用后置Logger方法进行日志记录");
    }

    //环绕通知
    public Object arroundMethod(ProceedingJoinPoint pjp){
        Object obj=null;
        try{
            System.out.println("环绕---------前置通知");

            //切点方法
            Object[] args = pjp.getArgs();       //参数
            obj = pjp.proceed(args);      //调用切点的所有方法

            System.out.println("环绕---------返回通知");
        }catch (Throwable e){
            System.out.println("环绕---------异常通知");
        }finally {
            System.out.println("环绕---------后置通知");
            return obj;
        }

    }
}

//applicationContext.xml
<!--注入业务层-->
    <bean id="accountServiceImp" class="com.apesource.service.AccountServiceImp"></bean>
    <!--注入日志记录层-->
    <bean id="logger" class="com.apesource.util.Logger"></bean>

    <!--配置AOP-->
    <aop:config>
        <!--配置切面-->
        <aop:aspect id="aopAspect" ref="logger">
            <!--配置通知类型,并建立通知方法和切入点方法的关联-->
            <!--切点 expression = execution(修饰符{可省略} 返回值 包名称.类名称.方法名称(参数列表))-->
            <aop:pointcut id="dian" expression="execution(* com.apesource.service.*.*(..))"/>
            <!--通知-->
<!--            <aop:before method="brforeLogger" pointcut-ref="dian"></aop:before>-->
<!--            <aop:after-returning method="returnLogger" pointcut-ref="dian"/>-->
<!--            <aop:after-throwing method="throwLogger" pointcut-ref="dian"/>-->
<!--            <aop:after method="afterLogger" pointcut-ref="dian"/>-->
            <aop:around method="arroundMethod" pointcut-ref="dian"/>
        </aop:aspect>
    </aop:config>

//测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class Test01 {

    @Autowired
    public IAccountService service;

    @Test
    public void show1(){
        service.update();
        System.out.println("----------");
        service.save(1);
        System.out.println("-----------");
        service.delete();
    }
}

注解版的面向切面编程案例部分代码展示

//logger日志
@Component
@Aspect     //切面
public class Logger {
    @Pointcut("execution(* com.apesource.service.*.*(..))")
    public void dian(){

    }

    @Before("dian()")
    public void beforeLogger(){
        System.out.println("日志类logger中调用前置Logger方法进行日志记录");
    }
    @AfterReturning("dian()")
    public void returnLogger(){
        System.out.println("日志类logger中调用返回Logger方法进行日志记录");
    }
    @AfterThrowing("dian()")
    public void throwLogger(){
        System.out.println("日志类logger中调用异常Logger方法进行日志记录");
    }
    @After("dian()")
    public void afterLogger(){
        System.out.println("日志类logger中调用后置Logger方法进行日志记录");
    }

    //环绕通知
//    @Around("dian()")
    public Object arroundMethod(ProceedingJoinPoint pjp){
        Object obj=null;   //保存主业务犯法的返回值
        try{
            System.out.println("环绕---------前置通知");

            //切点方法
            Object[] args = pjp.getArgs();       //参数
            obj = pjp.proceed(args);      //调用切点的所有方法

            System.out.println("环绕---------返回通知");
        }catch (Throwable e){
            System.out.println("环绕---------异常通知");
        }finally {
            System.out.println("环绕---------后置通知");
            return obj;
        }

    }
}

//applicationContext.xml
    <!--扫描-->
    <context:component-scan base-package="com.apesource"></context:component-scan>
    <!--开启spring注解的aop动态代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

标签:Java,void,System,class,AOP,println,设计模式,public,out
From: https://blog.csdn.net/weixin_64562166/article/details/141032450

相关文章

  • Java方法06:递归
    A方法调用B方法,我们很容易理解!递归就是:A方法调用A方法!就是自己调用自己,因此我们在设计递归算法时,一定要指明什么时候自己不调用自己。否则,就是个死循环!递归算法重点:递归是一种常见的解决问题的方法,即把问题逐渐简单化。递归的基本思想就是“自己调用自己”,一个使用递归技术的方......
  • Java方法03:方法的重载
    上面使用的max方法仅仅适用于int型数据。但如果你想得到两个浮点类型数据的最大值呢?解决方法是创建另一个有相同名字但参数不同的方法,如下面代码所示:publicstaticdoublemax(doublenum1,doublenum2){ if(num1>num2){ returnnum1; }else{ returnnum2; }}......
  • Java方法04:拓展命令行传参
    有时候你希望运行一个程序时候再传递给它消息。这要靠传递命令行参数给main()函数实现。命令行参数是在执行程序时候紧跟在程序名字后面的信息。【下面的程序打印所有的命令行参数】publicclassCommandLine{ publicstaticvoidmain(Stringargs[]){ for(inti=0;i<arg......
  • Java方法05:可变参数
    JDK1.5开始,Java支持传递同类型的可变参数给一个方法。方法的可变参数的声明如下所示:typeName...parameterName在方法声明中,在指定参数类型后加一个省略号(...)。一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。publicsta......
  • 基于java的可视化高校公寓管理系统(10621)
     有需要的同学,源代码和配套文档领取,加文章最下方的名片哦一、项目演示项目演示视频二、资料介绍完整源代码(前后端源代码+SQL脚本)配套文档(LW+PPT+开题报告)远程调试控屏包运行三、技术介绍Java语言SSM框架SpringBoot框架Vue框架JSP页面Mysql数据库IDEA/Eclipse开发四、项......
  • 基于javaweb的数学竞赛网站的设计与实现(10669)
     有需要的同学,源代码和配套文档领取,加文章最下方的名片哦一、项目演示项目演示视频二、资料介绍完整源代码(前后端源代码+SQL脚本)配套文档(LW+PPT+开题报告)远程调试控屏包运行三、技术介绍Java语言SSM框架SpringBoot框架Vue框架JSP页面Mysql数据库IDEA/Eclipse开发四、项......
  • Java方法02:方法调用
    Java支持两种调用方法的方式,根据方法是否返回值来选择。当程序调用一个方法时,程序的控制权交给了被调用的方法。当被调用方法的返回语句执行或者到达方法体闭括号时候交还控制权给程序。当方法返回一个值的时候,方法调用通常被当做一个值。例如:intlarger=max(30,40);Java......
  • Java方法01:方法的定义
    在之前的学习中我们经常使用到System.out.println(),那么它是什么呢?println()是一个方法。System是系统类。out是标准输出对象。这句话的用法是调用系统类System中的标准输出对象out中的方法println()。那么什么是方法呢?Java方法是语句的集合,它们在一起执行一个功......
  • 在一串字符串中Java使用正则匹配电话号码的方法
    1.使用正则表达式来匹配电话号码在Java中,使用正则表达式匹配电话号码是一个常见的需求。电话号码的格式可能因国家/地区而异,但一个典型的格式可能是这样的:(123)456-7890。在这个例子中,我将提供一个Java程序,该程序使用正则表达式来匹配这种格式的电话号码。首先,我们需要了解电话......
  • 【JavaEE初阶】常见的锁策略
    目录......