osgi 模块化_OSGI –模块化您的应用程序

osgi 模块化

由于我是模块化,低耦合,高凝聚力等的大力拥护者,所以……
我相信这项技术是我们使用Java平台创建应用程序的突破。 使用OSGi,创建高度可扩展的应用程序非常简单,例如参见Eclipse IDE。 我的目的不是要深入展示该技术的工作原理,而是要举例说明其某些优势。 该示例包含一个用于发送消息的系统。 用户在TextField中键入一条消息,然后可以通过多种方式发送该消息,例如Email或SMS。 但是,在此示例中,我们有四个模块。 图形用户界面,域,电子邮件的发件人以及通过SMS的发件人。

遵循OSGi的术语,每个模块都是一个捆绑包。 捆绑包不过是一个“罐子”,其中包含MANIFEST.MF的一些附加信息。 此信息由OSGi框架使用。 像Java中的几乎所有内容一样,OSGi技术是一种规范,因此有不同的实现方式可供选择。 其中最著名的是Equinox(Eclipse项目),Felix(Apache)和Knopflerfish。 在本文中,我们将使用Equinox。

下载Equinox。 对于本文,我们只需要罐子即可。 运行jar以访问Equinox的控制台。

C:\osgi>java -jar org.eclipse.osgi_3.5.1.R35x_v20090827.jar –console

要查看已安装的捆绑包,只需键入命令ss。

C:\osgi>java -jar org.eclipse.osgi_3.5.1.R35x_v20090827.jar – console
osgi> ss

框架启动。

id State Bundle<
0 ACTIVE org.eclipse.osgi_3.5.1.R35x_v20090827
osgi> _

正如我们现在所看到的,我们仅安装了一个捆绑软件。 春分包。
现在,我们将创建捆绑包并将其添加到Equinox。 创建捆绑包非常简单。
使用以下类创建一个简单的项目:

package br.com.luiscm.helloworld;import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;public class Activator implements BundleActivator {/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)*/public void start(BundleContext context) throws Exception {System.out.println("Hello World!");}/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)*/public void stop(BundleContext context) throws Exception {System.out.println("Good Bye World!");}
}

此类是我们捆绑软件的激活器。 OSGi框架使用激活器来启动或停止捆绑软件。 在第一个示例中,激活器仅在启动和停止时才打印消息。 现在,我们需要修改jar的清单以使其成为OSGi捆绑包。

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: LuisCM Plug-in
Bundle-SymbolicName: br.com.luiscm.helloworld
Bundle-Version: 1.0.0
Bundle-Activator: br.com.luiscm.helloworld.Activator
Bundle-ActivationPolicy: lazy
Bundle-RequiredExcutionEnvironment: JavaSE-1.6
Import-Package: org.osgi.framework;version=”1.3.0?

请参阅传递给OSGi捆绑软件的清单,以了解我们的一些信息。 其中的束名称(SymbolicName)和Activator类。 现在让我们在Equinox中安装此捆绑包。 生成项目的jar并将其安装在Equinox中很简单:

install file:.jar
osgi> install file:bundle.jar
Bundle id is 1
osgi>

要验证是否正确安装了捆绑软件,只需运行命令ss:

osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.1.R35x_v20090827
1 INSTALLED br.com.luiscm.helloworld_1.0.0
osgi> _

该捆绑包已正确安装,您现在就可以启动它:

start
osgi> start 1
Hello World!
osgi>

停止捆绑包:

osgi> stop 1
Goodbye World!
osgi>

现在我们知道如何创建捆绑包,让我们开始示例。 在示例中,我们有四个捆绑包。

*域:顾名思义,它在我们的示例中存储域类。 我们将有两个类:Message和IMessageSender。
* SenderSMS:通过短信发送消息的IMessageSender实现。
* SenderEmail:实现通过电子邮件发送消息的IMessageSender。 * UI:GUI示例

捆绑用户界面

我们将从UI捆绑包开始。 激活器将为用户输入消息建立框架。

package br.com.luiscm.helloworld;import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;import br.com.luiscm.helloworld.core.service.Message;public class Activator implements BundleActivator {private Message message;private JFrame frame;/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)*/public void start(BundleContext context) throws Exception {buildInterface();}/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)*/public void stop(BundleContext context) throws Exception {destroyInterface();}private void destroyInterface() {frame.setVisible(false);frame.dispose();}private void buildInterface() {frame = new JFrame("Hello");frame.setSize(200, 80);frame.getContentPane().setLayout(new BorderLayout());final JTextField textField = new JTextField();final JButton button = new JButton("Send");button.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent event) {message.send(textField.getText());}});frame.getContentPane().add(textField, BorderLayout.NORTH);frame.getContentPane().add(button, BorderLayout.SOUTH);frame.setVisible(true);}
}

请注意,该捆绑包取决于一个称为Message的类。 此类是我们的领域,因此不属于此捆绑包。 这是OSGi的另一个细节。 通信是通过捆绑服务完成的。 我们可以将此模型视为VM中的SOA。 服务包UI将使用包核心。 让我们看一下MANIFEST包UI。

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: UI Plug-in
Bundle-SymbolicName: br.com.luiscm.helloworld.ui<
Bundle-Version: 1.0.0
Bundle-Activator: br.com.luiscm.helloworld.ui.Activator
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: br.com.luiscm.helloworld.core.service,
javax.swing,
org.osgi.framework;version=”1.3.0?,
org.osgi.util.tracker;version=”1.3.6?

请参阅Import-Package语句。 我们正在导入软件包捆绑包核心。 此程序包中包含我们领域提供的服务。 还要导入javax.swing包。

现在我们需要创建服务。

捆绑核心

核心捆绑包有两个域类。 发件人的界面和“消息”字段。

接口:

package br.com.luiscm.helloworld.core.service;public interface IMessageSender {void send(String message);
}

域:

package br.com.luiscm.helloworld.core.service;import java.util.ArrayList;
import java.util.List;public class Message {private final List services = new ArrayList();public void addService(final IMessageSender messageSender) {services.add(messageSender);}public void removeService(final IMessageSender messageSender) {services.remove(messageSender);}public void send(final String message) {for (final IMessageSender messageSender : services) {messageSender.send(message);}}
}

请参阅Message类,其中包含服务列表。 这些服务是要使用的消息的发送者。 请注意,send方法仅在邮件列表消息上交互。 到目前为止,一切都非常简单。 现在,我们需要将Message类导出为核心服务包。 UI模块将直接与此服务交互以发送消息。

首先,我们需要告诉它将OSGi捆绑包导出到其他捆绑包。 参见清单:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Helloworld Plugin
Bundle-SymbolicName: br.com.luiscm.helloworld.core
Bundle-Version: 1.0.0
Bundle-Activator: br.com.luiscm.helloworld.core.Activator
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: org.osgi.framework;version=”1.3.0?,
org.osgi.util.tracker;version=”1.3.6?
Export-Package: br.com.luiscm.helloworld.core.service

请参阅信息导出包。 为了使一个类对于另一个捆绑包可见,必须将其导出到包中。 在我们的例子中,UI需要捆绑Message类,因此我们需要将包导出到该类所在的位置。 请记住,UI导入了捆绑包。

消息要将组件注册为服务,我们需要直接与OSGi API进行交互。 启动核心捆绑包后,我们将在OSGi上下文中注册服务。 代码很简单:

package br.com.luiscm.helloworld.core;import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;public class Activator implements BundleActivator {/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)*/public void start(BundleContext context) throws Exception {context.registerService(Message.class.getName(), messageService, null);}/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)*/public void stop(BundleContext context) throws Exception {messageService = null;}
}

方法registerService期望参数为服务名称(建议使用类名称),服务本身以及一些其他设置。

现在,我们需要更改UI以使用捆绑消息服务。 在bundle activator UI中,只需使用您的名字(类名)进行查找服务即可:

private Message message;private JFrame frame;private ServiceTracker serviceTracker;/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)*/public void start(BundleContext context) throws Exception {serviceTracker = new ServiceTracker(context, Message.class.getName(), null);serviceTracker.open();message = (Message)serviceTracker.getService();buildInterface();}/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)*/public void stop(BundleContext context) throws Exception {destroyInterface();serviceTracker.close();}
}

如果在Equinox中添加两个捆绑包,我们将看到两个捆绑包正在通信。 现在,我们需要创建实际发送消息的包。

捆绑发件人电子邮件和短信

通过电子邮件和SMS的运输服务将是我们系统中的新服务。 因此,我们为每个创建一个包。 这样我们可以分别控制它们。 例如,我们可以通过发送短信来停止服务,而只留下电子邮件,而不会影响系统操作。 这两个捆绑包实际上具有相同的结构,因此我将在此处保存一些行。

发件人只有一个实现接口的捆绑软件类和IMessageSender Activator类。 该接口位于核心捆绑包中,因此我们需要以与捆绑包UI中相同的方式导入包。

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-name: SMS Plug-in
Bundle-SymbolicName: br.com.luiscm.helloworld.sms.Activator<
Bundle-Version: 1.0.0
Bundle-Activator: br.com.luiscm.helloworld.sms.Activator
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Import-Package: br.com.luiscm.helloworld.core.service,
org.osgi.framework;version=”1.3.0?

Sender唯一的类实现我们的接口:

package br.com.luiscm.helloworld.sms;import br.com.luiscm.helloworld.core.service.IMessageSender;public class MessageSenderSMS implements IMessageSender {@Overridepublic void send(final String message) {System.out.println("Sending by SMS : " + message);}
}

通过短信发送是我们系统的一项服务。 因此,我们必须在OSGi上下文中注册它:

public class Activator implements BundleActivator {private IMessageSender service;/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)*/public void start(BundleContext context) throws Exception {service = new MessageSenderSMS();context.registerService(IMessageSender.class.getName(), service, null);}/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)*/public void stop(BundleContext context) throws Exception {service = null;}
}

邮件束实际上是相同的代码。 唯一的区别是System.out上的消息。

请注意,已使用接口名称注册了该服务。 因此,现在我们有两个具有相同名称的服务。 每当我们要求使用接口名称的服务上下文时,他都会执行逻辑优先级以仅返回一个实现。

现在我们有两个用于发送消息的服务,我们需要更改我们的包核心以使用它们。 为了实现此目标,请使用ServiceTrackerCustomizer。

ServiceTrackerCustomizer和ServiceTracker

如我们所见,我们曾经做Servicetrack查找服务。 但是,对于发送者,我们需要知道何时有新的发送者服务可用或何时删除发送者。 此信息对于在Message对象中提供服务列表很重要。

要访问此信息,我们使用ServiceTrackerCustomizer。 代码很简单:

package br.com.luiscm.helloworld.core;import org.osgi.framework.BundleContext;public class MessageSenderServiceTracker implements ServiceTrackerCustomizer {private final BundleContext context;private final Message message;public MessageSenderServiceTracker(final BundleContext context, final Message message) {this.context = context;this.message = message;}@Overridepublic Object addingService(final ServiceReference serviceReference) {final IMessageSender sender = (IMessageSender)context.getService(serviceReference);message.addService(sender);System.out.println("tracker : " + sender.getClass().getName());return sender;}@Overridepublic void removedService(final ServiceReference serviceReference, Object service) {final IMessageSender sender = (IMessageSender)context.getService(serviceReference);message.removeService(sender);}
}

只需实现接口,并在添加,修改或删除服务时根据需要编写ServiceTrackerCustomizer代码即可。 简单!

在我们的例子中,我们将在Message对象的服务列表中添加或删除服务。 还带有一条“日志”消息,以帮助我们进行测试。

现在,我们需要对bundle核心激活器进行另一项较小的更改。 我们必须将ServiceTrackerCustomizer注册为诸如IMessageSender之类的服务的侦听器。

public class Activator implements BundleActivator {public Message messageService = new Message();private ServiceTracker messageSenderServiceTracker;/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)*/public void start(BundleContext context) throws Exception {context.registerService(Message.class.getName(), messageService, null);final MessageSenderServiceTracker serviceTracker = new MessageSenderServiceTracker(context, messageService);messageSenderServiceTracker = new ServiceTracker(context, IMessageSender.class.getName(), serviceTracker);messageSenderServiceTracker.open();}/** (non-Javadoc)* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)*/public void stop(BundleContext context) throws Exception {messageSenderServiceTracker.close();messageService = null;}
}

我们将ServiceTrackerCustomizer与ServiceTtracker一起使用。 在添加,修改或删除服务的地方,我们的组件将被调用。

测试应用程序

现在我们进行编码,我们测试应用程序。

创建四个罐子:

* bundleCore.jar
* bundleUI.jar
* bundleSenderEmail.jar * bundleSenderSMS.jar

在Equinox中安装四个捆绑包:

框架启动。

id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.1.R35x_20090827.jar
osgi> install file:bundleCore.jar
Bundle id is 5
osgi> install file:bundleUI.jar
Bundle id is 6
osgi> install file:bundleSenderEmail.jar
Bundle id is 7
osgi> install file:bundleSenderSMS.jar
Bundle id is 8
osgi> ss

框架启动。

0 ACTIVE org.eclipse.osgi._3.5.1.R35x_v20090827.jar
5 INSTALLED br.com.luiscm.helloworld.core_1.0.0
6 INSTALLED br.com.luiscm.helloworld.ui_1.0.0
7 INSTALLED br.com.luiscm.helloworld.email_1.0.0
8 INSTALLED br.com.luiscm.helloworld.sms_1.0.0

启动捆绑包并测试应用程序。

C:\osgi>java -jar org.eclipse.osgi._3.5.1.R35x_v20090827.jar -console
osgi> tracker: br.com.luiscm.heloworld.sms.SenderSMStracker: br.com.luiscm.helloworld.email.SenderEmail

查看通过电子邮件和SMS发送的消息。 在控制台Equinox中,暂停服务电子邮件:

stop

再试一次发送消息。 由于该服务不再可用,因此该消息仅由SMS发送。

停止电源应用程序模块而不会产生副作用是非常明智的。 想象一下,您在SMS模块中发现了一个严重错误。 您无需花费所有精力即可解决此问题。 只需暂停SMS模块。 系统的其余部分将继续正常运行。 通过这个小例子进行测试。 暂停和启动服务。 这不会影响核心,更不会影响UI。

我设法解释了什么是OSGi。 值得注意的是,这里有关于控制和类路径配置包的更多详细信息,此处不再关注。 这是那些有兴趣的人看看其他功能的任务。

值得一看Spring-DM项目。 除了提供出色的IoC容器外,弹簧还使设置服务变得非常容易。

参考: OSGI –在Eclipse Brazil博客上,由我们的JCG合作伙伴 Luis Carlos Moreira da Costa 模块化您的应用程序 。


翻译自: https://www.javacodegeeks.com/2012/04/osgi-modularizing-your-application.html

osgi 模块化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/355824.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电脑计算器_CPA考生注意!2020考场只允许带这种计算器

注册会计师每年采用闭卷、计算机化考试方式。根据往年考生的反应&#xff0c;计算器的使用在考场上发挥了非常大的作用。值得大家注意的是&#xff0c;并不是所有的计算器都能带进考场&#xff0c;考试对计算器有什么要求?如何挑选到正确的计算器&#xff1f;我们一起来看看&a…

最早的齿轮计算机,世界最古老“计算机”出土后110年,科学家终于解开它的秘密...

伦敦大学学院(UCL)的研究团队&#xff0c;提出了“一个激进的新模型&#xff0c;与所有数据相匹配&#xff0c;并最终优雅地展示出了古希腊人眼中的宇宙”。1901年&#xff0c;在希腊岛屿安提基特拉的海岸&#xff0c;潜水员偶然发现了一艘古代沉船。沉船中的一件文物&#xff…

通过Java 8中的Applicative Builder组合多个异步结果

几个月前&#xff0c;我发布了一个出版物 &#xff0c;在其中详细解释了我提出的名为Outcome的抽象&#xff0c;它通过强制使用语义帮助了我很多 没有副作用的代码。 通过遵循这种简单&#xff08;但功能强大&#xff09;的约定&#xff0c;我最终将任何类型的故障&#xff08;…

在python中是否可以使用if作为变量名_在Python中可以使用if 作为变量名_python使用符号 标示注释...

在Python中可以使用if 作为变量名答&#xff1a;" src"" style"max-width: 100%; display: inline;">往来款项清查结果的账务处理与货币资金、存货和固定资产不同&#xff0c;它不通过“待处理财产损溢”账户。答&#xff1a;√明嘉靖皇帝是昏君答…

diskgenius 接触“只读“失败_相亲总是失败,这三个步骤你都做了吗?

原标题&#xff1a;相亲总是失败&#xff0c;这三个步骤你都做了吗&#xff1f;虽然现在爱情很稀缺&#xff0c;但想必大家都想找个男女朋友&#xff0c;想谈一场甜甜的恋爱。 而相亲&#xff0c;无疑是脱单最直接、最有效的方式&#xff0c;没有之一。但不管是经人介绍&#x…

shell中的常用通配符,字符类

因为 shell 频繁 地使用文件名&#xff0c;shell 提供了特殊字符来帮助你快速指定一组文件名。这些特殊字符叫做通配符。 通配符     意义 *         匹配任意多个字符&#xff08;包括零个或一个&#xff09;  ?         匹配任意一个字符&…

agv系统介绍_重载AGV小车主要结构及导航原理是什么?

相信对AGV有过了解的朋友都知道&#xff0c;当我们在进行工业生产过程时&#xff0c;重载AGV小车可以帮我们实现无人驾驶搬运的一个工作&#xff0c;可以保证AGV在运行时不用通过人工干预的情况下来完成现场的搬运工作,通过无人驾驶技术进行自主导航将货物自动从起始位置搬运到…

怎样打开计算机音频服务器,win10系统音频服务器未运行的修复步骤

有关win10系统音频服务器未运行的操作方法想必大家有所耳闻。但是能够对win10系统音频服务器未运行进行实际操作的人却不多。其实解决win10系统音频服务器未运行的问题也不是难事&#xff0c;小编这里提示两点&#xff1a;1、在1、windows10“音频服务未运行”,有个红色小叉咋办…

rgb fusion检测不到显卡_【论文阅读27】Co-Fusion

主要内容物体级别的语义SLAM。维护一个背景模型和多物体模型&#xff0c;每个模型由面元地图表示。基于运动分割和语义信息检测运动物体。使用基于ICP对齐的几何误差和基于颜色差异的光度误差跟踪背景模型&#xff08;相机位姿&#xff09;和多个运动物体。根据[8]的方法更新每…

修改linux系统用户最大线程数限制

linux系统对线程数量有个最大限制&#xff0c;当达到系统限制的最大线程数时使用账号密码ssh到系统时是无法登陆的&#xff0c;会报Write failed: Broken pipe&#xff0c;或者是shell request faied on chanel 0。在root用户下切换到该用户也会报错&#xff0c;su clouder&…

u盘插在电脑上灯亮没有反应_u盘插入电脑无反应怎么解决 u盘插入电脑无反应解决方法【步骤介绍】...

u盘的轻巧、便捷使其在生活工作中重要的工具设备&#xff0c;在使用u盘的过程中插入的 u盘无法识别 &#xff0c;电脑对插入的u盘无反应&#xff0c;遇到这样的问题该怎么办呢?接下来小编就和大家介绍 电脑无法识别u盘 的解决办法。1 、使用其它的移动设备插在电脑usb接口上&a…

recaptcha_与reCAPTCHA的Spring集成

recaptcha有时我们只需要CAPTCHA &#xff0c;这是一个可悲的事实。 今天&#xff0c;我们将学习如何与reCAPTCHA集成。 因为主题本身并不是特别有趣和高级&#xff0c;所以我们将通过使用Spring Integration处理低级细节来过度设计&#xff08;&#xff1f;&#xff09;。 Goo…

vbs关不掉的计算机窗口,恶搞之关不掉的窗口.vbs脚本

过完小年&#xff0c;到处都是过年的气息&#xff0c;给大家介绍一些轻松好玩的东西&#xff1a;一个好玩的脚本——关不掉的窗口。1、在电脑上创建一个XXX.txt文本&#xff0c;把代码复制进去&#xff0c;不要写注释&#xff0c;也不要在句尾留空格&#xff0c;保存&#xff0…

honeywell新风系统控制面板说明_如何选择新风系统中的新风设备万家舒适家

喜欢点击蓝字关注我们吧我们常说“看人不光要看外表&#xff0c;更要看内在”&#xff0c;这个说法对新风机同样适用。新风机的内部件主要分为&#xff1a;动力模块、电控模块、净化模块、热交换模块这四个部分。首先、动力模块&#xff0c;就是风机。从我们消费者角度来看&…

第八周学习进度条

转载于:https://www.cnblogs.com/baiyue/p/7110849.html

keras 生成句子向量 词向量_在Keras模型中使用预训练的词向量

在Keras模型中使用预训练的词向量文章信息通过本教程&#xff0c;你可以掌握技能&#xff1a;使用预先训练的词向量和卷积神经网络解决一个文本分类问题本文代码已上传到Github本文作者&#xff1a;Francois Chollet什么是词向量?”词向量”(词嵌入)是将一类将词的语义映射到向…

设计模式的Java 8 Lambda表达式–策略设计模式

策略模式定义封装在通常称为Context的驱动程序类中的一系列算法&#xff0c;并使这些算法可互换。 它使算法易于互换&#xff0c;并提供了在特定时间选择适当算法的机制。 算法&#xff08;策略&#xff09;在运行时由客户端或上下文选择。 在与客户端交互期间&#xff0c;Con…

2016美国计算机研究生,2016美国留学:美国大学研究生计算机工程专业排名

排名学校名称学校英文名所在地学费/年1Massachusetts Instituteof TechnologyCambridge, MA$44,7201StanfordUniversityStanford, CA$47,0731University ofCalifornia—BerkeleyBerkeley, CA$26,3224卡耐基梅隆大学Carnegie MellonUniversityPittsburgh, PA$41,0005伊利诺伊大学…

hdu 4961 Boring Sum(高效)

题目链接&#xff1a;hdu 4961 Boring Sum 题目大意&#xff1a;给定ai数组; 构造bi, kmax(j|0<j<i,aj%ai0), biak;构造ci, kmin(j|i<j≤n,aj%ai0), ciak; 求∑i1nbi∗ci解题思路&#xff1a;由于ai≤105,所以预先处理好每一个数的因子&#xff0c;然后在处理bi&#…

sata修改为ahci后系统无法启动_固态重装系统

固态硬盘凭借其高速的读写速度&#xff0c;已经成为现如今很多用户电脑的标配。对于刚刚为电脑换上固态硬盘的用户来说&#xff0c;固态硬盘里并没有装有系统&#xff0c;因此首要任务就是进行重装系统win10。那么&#xff0c;固态硬盘如何装系统呢?为固态硬盘重装系统&#x…