python 开发的 windows版运维图形界面-信息管理系统
基于运维人员对windows/linux/网络设备系统管理比较分散,并且每个服务都要开启不同的监控和应用程序,浪费时间,浪费时间就是浪费金钱的道理没有人不会不懂这个道理,我查找了很多资源发现都是一些零散的监控工具,没有正真意思的统一监控管理(博主时间有限。目前只分享windows本地监控,后面继续更新远程监控),并且运维人员查看网络或者虚拟机信息都要远程登录,而本工具可以在本地直接写命令,获取远程配置信息,极大的提高运维人员的工作效率和节约成本时间。
1.登陆首页展示和代码分享
# 登陆页面 def log_in(self): """ 登录界面 :return: """ try: logging.info('***Stsrt IMS***') var1 = StringVar() # id框中的文字 var2 = StringVar() # 密码框中的文字 self.root.geometry('450x380' + self.winfo_landing_x + self.winfo_landing_y) # 设置主界面大小 self.root.resizable(0, 0) # 禁止调整窗口大小 self.root.title("信息化管理系统") # 登录主界面分成两行一列 logging.info('Start loading background image') # ================背景图================== # 组件.grid(row = x,column = y) 将组件放入self.root中(x,y)位置 f = Frame(width=523, height=150, bg='green') # frame1 canvas = tk.Canvas(self.root, width=525, height=150, bg='yellow') # canvas1 self.img = itk.PhotoImage(file="img/win.png") canvas.create_image(209, 75, image=self.img) canvas.grid(row=0, column=0, columnspan=2, padx=1, pady=3) # ======================================= logging.info('End loading background image') logging.info('Start loading the gray box') # ================下灰框================== f = Frame(width=520, height=220, bg='#DCDCDC') # frame2 f_head = Frame(width=80, height=80, bg='green') # frame3 # ======================================= logging.info('End loading the gray box') logging.info('Start loading avatar') # =================头像=================== self.canvas2 = tk.Canvas(self.root, width=80, height=80, bg='red') self.img2 = Img.open("img/TX.png") self.img2 = itk.PhotoImage(self.img2) self.canvas2.create_image(40, 40, image=self.img2) self.canvas2.place(in_=f_head, anchor=NW) # canvas2放入frame3中,位置是偏西北 f_head.place(relx=0.10, rely=0.56) # frame3放入root的绝对位置上 # ======================================= logging.info('End loading avatar') logging.info('Start loading user accounts') # ===============用户账号================== Entry1直接放入self.root的绝对位置上,也可以尝试放入frame2中 self.usr = Entry(self.root, textvariable=var1, bg='#F5F5F5', highlightcolor='#1E90FF') self.usr.place(relx=0.35, rely=0.56) # ======================================= logging.info('End loading user accounts') logging.info('Start loading the password box') # ===============密码框==================== Entry2 直接放入self.root的绝对位置上 self.pwd = Entry(self.root, textvariable=var2, bg='#F5F5F5', highlightcolor='#1E90FF') self.pwd['show'] = '*' self.pwd.place(relx=0.35, rely=0.65) # ======================================= logging.info('End loading the password box') logging.info('Start loading automatic login') # 自动登录 # checkbutton 放入绝对位置 rem_pwd = Checkbutton(self.root, foreground='#1E90FF').place(relx=0.34, rely=0.72) # 选择框 # 设置颜色,字体,宽,长 compound=LEFT, foreground='#808080', bg='#DCDCDC' rem_pwd_lab = Label(self.root, width=6, height=1, text='自动登录', foreground='#808080') rem_pwd_lab.place(relx=0.39, rely=0.72) # ======================================= logging.info('End loading automatic login') logging.info('Start loading the remember password') # ==============记住密码=================== rem_pwd = Checkbutton(self.root, foreground='#1E90FF').place(relx=0.51, rely=0.72) # 选择框 rem_pwd_lab = Label(self.root, width=6, height=1, text='记住密码', foreground='#808080') # 设置颜色,字体,宽,长 compound=LEFT, foreground='#808080', bg='#DCDCDC' rem_pwd_lab.place(relx=0.56, rely=0.72) # 设计找回密码字体大小 # ======================================= logging.info('End loading the remember password') # =============登录按钮==================== login_btn = Button(self.root, text=' 登陆 ', bg='#1E90FF') # 按钮,字体颜色,按钮背景色:bg='#1E90FF' login_btn.place(relx=0.36, rely=0.8) # 设置登录坐标位置X,Y login_btn.bind("<Button-1>", self.load) # 触发函数执行 # ======================================= # ===============注册用户================== fgt_usr_btn = Button(self.root, text='注册账号', foreground='#1E90FF', command=self.regiser) # 灰色:bg='#DCDCDC' fgt_usr_btn.place(relx=0.7, rely=0.54) # fgt_usr_btn.bind("<Button-1>", self.regiser) # ======================================= # ===============找回密码================= fgt_pwd_btn = Button(self.root, text='找回密码', foreground='#1E90FF', command=self.fg_pwd) # 灰色:bg='#DCDCDC' fgt_pwd_btn.place(relx=0.7, rely=0.64) # fgt_pwd_btn.bind("<Button-1>", self.fg_pwd) #模拟enter按钮 # fgt_pwd_btn.flash() # ======================================= except Exception as loginerror: logging.info(str(loginerror)) print(str(loginerror)) # 登陆认证 def load(self, *args): """ 登录事件 :param args: :return: """ try: logging.info('Start running the login event ') user = self.usr.get() pwd = self.pwd.get() License_p = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) hl = hashlib.md5() hl.update(pwd.encode(encoding='utf8')) pwd_md5_jm = hl.hexdigest() print('加密前为 :' + pwd) print('加密后为 :' + hl.hexdigest()) if License_p <= self.LICENSE_TIMES: with open(r'db\imsap.txt', 'r', encoding='utf8') as f: for i in f: user1 = i.strip().split(':')[2] pwd2 = i.strip().split(':')[3] if user == user1 and pwd2 == pwd_md5_jm: # if self.username == user and self.password == pwd_md5_jm: logging.info('login successful') print('登录成功') self.root.quit() # 关闭登录窗口 self.root.destroy() # destroy()销毁一个小部件,quit()退出mainloop。 print('已关闭登陆界面。。') print('开始加载主页面。。') logging.info('Start loading page') # self.cs1() t1 = threading.Thread(target=self.cs1()) t1.start() t1.join() logging.info('End loading page') print('主页面加载结束。。') else: print('登录失败') lbtime2 = tk.Label(self.root, fg='red', anchor='w') lbtime2.place(x=156, y=180, width=150) lbtime2['text'] = '请输入正确的用户名或密码' # messagebox.showinfo(title='登陆日志', message='用户名或密码错误,请重新登录') else: lbtime2 = tk.Label(self.root, fg='red', anchor='w') lbtime2.place(x=149, y=180, width=155) lbtime2['text'] = 'License已过期,请联系管理员授权!' logging.info('End running the login event ') except Exception as ruuingerror: print(str(ruuingerror)) # 账号注册页面 def regiser(self, *args): """ 登录账号注册 :param event: :return: """ self.ycsy = tk.Tk() self.ycsy.title('登录账号注册') # 设置窗口标题 self.ycsy.geometry("580x265+460+300") # 设置窗口大小 宽,高 self.ycsy.resizable(width=False, height=False) # 宽不可变, 高可变,默认为True name = tk.StringVar() ttk.Label(self.ycsy, text="").grid(row=0, column=1, columnspan=1) tk.Label(self.ycsy, text="用户ID *", font=("黑体", 10, "bold"), width=40, height=3, wraplength=80, anchor='w').grid( row=1, column=1, columnspan=1) tk.Label(self.ycsy, text="用户名 *", font=("黑体", 10, "bold"), width=40, height=3, wraplength=80, anchor='w').grid( row=1, column=2, columnspan=1) self.name_id = tk.StringVar() self.name_id_sr = ttk.Entry(self.ycsy, width=20, textvariable=self.name_id) self.name_id_sr.grid(row=1, column=1) self.name_id_sr.focus() self.name_zc = tk.StringVar() self.name_zc_sr = ttk.Entry(self.ycsy, width=20, textvariable=self.name_zc) self.name_zc_sr.grid(row=1, column=2) self.name_zc_sr.focus() tk.Label(self.ycsy, text=u"账号状态", font=("黑体", 10, "bold"), width=40, height=3, wraplength=80, anchor='w').grid( row=2, column=1) tk.Label(self.ycsy, text=u"密码 *", font=("黑体", 10, "bold"), width=40, height=3, wraplength=80, anchor='w').grid( row=2, column=2) self.account_zc = tk.StringVar() self.account_zc_sr = ttk.Combobox(self.ycsy, width=18, textvariable=self.account_zc, state='readonly') # 下拉框字体,内容为weather,宽度,state='editable'表示内容可编辑 self.account_zc_sr['values'] = (' 可 用', ' 禁 用') # 设置下拉列表的值 self.account_zc_sr.grid(column=1, row=2) # 设置其在界面中出现的位置 column代表列 row 代表行 self.account_zc_sr.current(0) self.pwd_zc = tk.StringVar() self.pwd_zc_sr = ttk.Entry(self.ycsy, width=20, textvariable=self.pwd_zc, show='*') self.pwd_zc_sr.grid(row=2, column=2) self.pwd_zc_sr.focus() tk.Label(self.ycsy, text=u"邮箱 *", font=("黑体", 10, "bold"), width=40, height=3, wraplength=80, anchor='w').grid(row=3, column=1) tk.Label(self.ycsy, text=u"确认密码 *", font=("黑体", 10, "bold"), width=40, height=3, wraplength=80, anchor='w').grid(row=3, column=2) self.email_zc = tk.StringVar() self.email_zc_sr = ttk.Entry(self.ycsy, width=20, textvariable=self.email_zc) self.email_zc_sr.grid(row=3, column=1) self.email_zc_sr.focus() self.pwd_qr_zc = tk.StringVar() self.pwd_qr_zc_sr = ttk.Entry(self.ycsy, width=20, textvariable=self.pwd_qr_zc, show='*') self.pwd_qr_zc_sr.grid(row=3, column=2) self.pwd_qr_zc_sr.focus() tk.Label(self.ycsy, text=u"手机号码 *", font=("黑体", 10, "bold"), width=40, height=3, wraplength=80, anchor='w').grid(row=4, column=1) tk.Label(self.ycsy, text=u"信息安全", font=("黑体", 10, "bold"), width=40, height=3, wraplength=80, anchor='w').grid(row=4, column=2) self.phone_zc = tk.StringVar() self.phone_zc_sr = ttk.Entry(self.ycsy, width=20, textvariable=self.phone_zc) self.phone_zc_sr.grid(row=4, column=1) self.phone_zc_sr.focus() self.ifm_zc = tk.StringVar() self.ifm_zc_sr = ttk.Combobox(self.ycsy, width=18, textvariable=self.ifm_zc, state='readonly') self.ifm_zc_sr['values'] = (' 不加密', ' 加 密') # 设置下拉列表的值 self.ifm_zc_sr.grid(column=2, row=4) # 设置其在界面中出现的位置 column代表列 row 代表行 self.ifm_zc_sr.current(0) # =============注册确定按钮==================== # button3放入绝对位置 login_btn = Button(self.ycsy, text=' 确定 ', bg='#1E90FF', command=self.regiser_file) login_btn.place(relx=0.38, rely=0.8) # login_btn.bind("<Button-1>", '执行函数') # ======================================= # =============注册取消按钮==================== button3放入绝对位置 login_btn = Button(self.ycsy, text=' 关闭 ', bg='#1E90FF', command=self.regiser_cancel) login_btn.place(relx=0.49, rely=0.8) # login_btn.bind("<Button-1>", self.regiser_cancel) # ======================================= # 账号注册确定 def regiser_file(self, *args): """ 注册确定事件 :return: """ self.id_file_p = self.name_id_sr.get() # 用户ID self.name_file_p = self.name_zc_sr.get() # 用户名 self.accout_file_p = self.account_zc_sr.get() # 账号状态 self.pwd_file_p = self.pwd_zc_sr.get() # 密码 # 密码加密----------------------------------- hl = hashlib.md5() hl.update(self.pwd_file_p.encode(encoding='utf8')) self.pwd_file_p = hl.hexdigest() # 密码加密----------------------------------- self.email_file_p = self.email_zc_sr.get() # 邮箱 self.pwd_qr_file_p = self.pwd_qr_zc_sr.get() # 确认密码 self.phone_file_p = self.phone_zc_sr.get() # 手机号码 self.ifm_file_p = self.ifm_zc_sr.get() # 信息安全 if self.name_file_p or self.pwd_file_p or self.pwd_qr_file_p != '' and self.pwd_file_p != self.pwd_qr_file_p: # [IMSAP]:用户ID:用户名,密码,邮箱,手机号码,账号状态,信息安全 file_imsap = '[IMSAP]:{0}:{1}:{2}:{3}:{4}:{5}:{6}'.format( self.id_file_p, self.name_file_p, self.pwd_file_p, self.email_file_p, self.phone_file_p, self.accout_file_p, self.ifm_file_p, self.ifm_file_p ).replace(' ', '') with open(r'report\imsap.txt', 'a', encoding='utf8') as f: f.writelines(file_imsap + '\n') f.close() lbtime2 = tk.Label(self.ycsy, fg='red', anchor='w') lbtime2.place(x=205, y=2, width=160) lbtime2['text'] = '提示:已注册成功请登录' else: lbtime2 = tk.Label(self.ycsy, fg='red', anchor='w') lbtime2.place(x=210, y=2, width=160) lbtime2['text'] = '提示:带“*”为必填项!!' # # 密码 if self.pwd_file_p != self.pwd_qr_file_p: lbtime2 = tk.Label(self.ycsy, fg='red', anchor='w') lbtime2.place(x=205, y=2, width=160) lbtime2['text'] = '提示:密码不一致!!' # 账号注册取消 def regiser_cancel(self): """ 注册取消事件 :return: """ self.ycsy.destroy() # 找回密码 def fg_pwd(self, *args): """ 找回密码事件 :param event: :return: """ messagebox.showinfo(title='找回密码', message='程序正在更新中......')
1.1 代码执行效果图
2.代码监控部分逻辑代码
def fbytes(B): 'Return the given bytes as a human friendly KB, MB, GB, or TB string' B = float(B) KB = float(1024) MB = float(KB ** 2) # 1,048,576 GB = float(KB ** 3) # 1,073,741,824 TB = float(KB ** 4) # 1,099,511,627,776 if B < KB: return '{0} {1}'.format(B, 'Bytes' if 0 == B > 1 else 'Byte') elif KB <= B < MB: return '{0:.2f} KB'.format(B / KB) elif MB <= B < GB: return '{0:.2f} MB'.format(B / MB) elif GB <= B < TB: return '{0:.2f} GB'.format(B / GB) elif TB <= B: return '{0:.2f} TB'.format(B / TB) class Handler(http.server.BaseHTTPRequestHandler): """Simple HTTP request handler with GET/HEAD/POST commands. This serves files from the current directory and any of its subdirectories. The MIME type for files is determined by calling the .guess_type() method. And can reveive file uploaded by client. The GET/HEAD/POST requests are identical except that the HEAD request omits the actual contents of the file. """ def do_GET(self): """Serve a GET request.""" f = self.send_head() if f: self.copyfile(f, self.wfile) f.close() def do_HEAD(self): """Serve a HEAD request.""" f = self.send_head() if f: f.close() def do_POST(self): """Serve a POST request.""" r, info = self.deal_post_data() print((r, info, "by: ", self.client_address)) f = BytesIO() f.write(b'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">') f.write(b"<html>\n<title>Upload Result Page</title>\n") f.write(b'<style type="text/css">\n') f.write(b'* {font-family: Helvetica; font-size: 16px; }\n') f.write(b'a { text-decoration: none; }\n') f.write(b'</style>\n') f.write(b"<body>\n<h2>Upload Result Page</h2>\n") f.write(b"<hr>\n") if r: f.write(b"<strong>Success!</strong>") else: f.write(b"<strong>Failed!</strong>") f.write(info.encode()) f.write(("<br><br><a href=\"%s\">" % self.headers['referer']).encode()) f.write(b"<button>Back</button></a>\n") f.write(b"<hr><small>Powered By: bones7456<br>Check new version ") f.write(b"<a href=\"https://gist.github.com/UniIsland/3346170\" target=\"_blank\">") f.write(b"here</a>.</small></body>\n</html>\n") length = f.tell() f.seek(0) self.send_response(200) self.send_header("Content-type", "text/html") self.send_header("Content-Length", str(length)) self.end_headers() if f: self.copyfile(f, self.wfile) f.close() def deal_post_data(self): uploaded_files = [] content_type = self.headers['content-type'] if not content_type: return (False, "Content-Type header doesn't contain boundary") boundary = content_type.split("=")[1].encode() remainbytes = int(self.headers['content-length']) line = self.rfile.readline() remainbytes -= len(line) if not boundary in line: return (False, "Content NOT begin with boundary") while remainbytes > 0: line = self.rfile.readline() remainbytes -= len(line) fn = re.findall(r'Content-Disposition.*name="file"; filename="(.*)"', line.decode()) if not fn: return (False, "Can't find out file name...") path = self.translate_path(self.path) fn = os.path.join(path, fn[0]) line = self.rfile.readline() remainbytes -= len(line) line = self.rfile.readline() remainbytes -= len(line) try: out = open(fn, 'wb') except IOError: return (False, "<br><br>Can't create file to write.<br>Do you have permission to write?") else: with out: preline = self.rfile.readline() remainbytes -= len(preline) while remainbytes > 0: line = self.rfile.readline() remainbytes -= len(line) if boundary in line: preline = preline[0:-1] if preline.endswith(b'\r'): preline = preline[0:-1] out.write(preline) uploaded_files.append(fn) break else: out.write(preline) preline = line return (True, "<br><br>'%s'" % "'<br>'".join(uploaded_files)) def send_head(self): """Common code for GET and HEAD commands. This sends the response code and MIME headers. Return value is either a file object (which has to be copied to the outputfile by the caller unless the command was HEAD, and must be closed by the caller under all circumstances), or None, in which case the caller has nothing further to do. """ path = self.translate_path(self.path) f = None if os.path.isdir(path): if not self.path.endswith('/'): # redirect browser - doing basically what apache does self.send_response(301) self.send_header("Location", self.path + "/") self.end_headers() return None for index in "index.html", "index.htm": index = os.path.join(path, index) if os.path.exists(index): path = index break else: return self.list_directory(path) ctype = self.guess_type(path) try: # Always read in binary mode. Opening files in text mode may cause # newline translations, making the actual size of the content # transmitted *less* than the content-length! f = open(path, 'rb') except IOError: self.send_error(404, "File not found") return None self.send_response(200) self.send_header("Content-type", ctype) fs = os.fstat(f.fileno()) self.send_header("Content-Length", str(fs[6])) self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) self.end_headers() return f def list_directory(self, path): """Helper to produce a directory listing (absent index.html). Return value is either a file object, or None (indicating an error). In either case, the headers are sent, making the interface the same as for send_head(). """ try: list = os.listdir(path) except os.error: self.send_error(404, "No permission to list directory") return None enc = sys.getfilesystemencoding() list.sort(key=lambda a: a.lower()) f = BytesIO() displaypath = html.escape(urllib.parse.unquote(self.path)) f.write(b'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">') f.write(b'<html>\n') f.write(('<meta http-equiv="Content-Type" ' 'content="text/html; charset=%s">' % enc).encode(enc)) f.write(("<title>Directory listing for %s</title>\n" % displaypath).encode(enc)) f.write(b'<style type="text/css">\n') f.write(b'* {font-family: Helvetica; font-size: 16px; }\n') f.write(b'a { text-decoration: none; }\n') f.write(b'a:link { text-decoration: none; font-weight: bold; color: #0000ff; }\n') f.write(b'a:visited { text-decoration: none; font-weight: bold; color: #0000ff; }\n') f.write(b'a:active { text-decoration: none; font-weight: bold; color: #0000ff; }\n') f.write(b'a:hover { text-decoration: none; font-weight: bold; color: #ff0000; }\n') f.write(b'table {\n border-collapse: separate;\n}\n') class VrvAgent(): """主逻辑""" def __init__(self): self.app = wx.App() # 创建应用程序对象 self.win = wx.Frame(None, -1, title='设备配置管理系统', size=(710, 620), pos=(500, 100), style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.MINIMIZE_BOX) # 创建窗体 self.taskBarIcon = TaskBarIcon(frame=self.win) self.agent_menu() # 菜单栏 self.agent_box() # 页面 def agent_menu(self): """ 总菜单栏 :return: """ self.memBar = wx.MenuBar() # 初始化菜单栏 self.agent_fileMenu_f() # 文件 self.agent_deitMenu_e() # 编辑 self.agent_helpMenu_h() # 帮助 self.win.SetMenuBar(self.memBar) # 启动菜单栏 def agent_fileMenu_f(self): """ 菜单栏 - 文件 :return: """ # ------------------------------文件 file_menu = wx.Menu() # 二级 newItem = wx.MenuItem(file_menu, id=wx.ID_NEW, text="新建(N)\tCtrl+N", kind=wx.ITEM_NORMAL) openItem = wx.MenuItem(file_menu, id=wx.ID_OPEN, text="打开(O)...\tCtrl+O", kind=wx.ITEM_NORMAL) saveItem = wx.MenuItem(file_menu, id=wx.ID_SAVE, text="保存(S)\tCtrl+S", kind=wx.ITEM_NORMAL) # saveItem.SetBitmap(wx.Bitmap("exit.png")) #添加保存图标 saveasItem = wx.MenuItem(file_menu, id=wx.ID_SAVEAS, text="另存为(A)...", kind=wx.ITEM_NORMAL) exitItem = wx.MenuItem(file_menu, id=20, text="退出(X)", kind=wx.ITEM_NORMAL) file_menu.Append(newItem) # newItem此属性添加带菜单栏 file_menu.Append(openItem) file_menu.Append(saveItem) file_menu.Append(saveasItem) file_menu.AppendSeparator() # 选项之间添加一行线 file_menu.Append(exitItem) self.win.Bind(wx.EVT_MENU, self.OnExit, saveasItem) # 执行另存为函数 self.win.Bind(wx.EVT_MENU, self.OnExit, exitItem) # 执行退出函数 self.memBar.Append(file_menu, title="文件(F)") # 一级 # ------------------------------文件 def agent_deitMenu_e(self): """ 菜单栏 - 编辑 :return: """ deitMenu = wx.Menu() ftpclient = wx.MenuItem(id=21, text="FTP客户端\tCtrl+W", kind=wx.ITEM_NORMAL) ftpserver = wx.MenuItem(id=21, text="FTP服务端\tCtrl+Q", kind=wx.ITEM_NORMAL) # deitMenu.Append(id=21, item="FTP服务端\tCtrl+Q", kind=wx.ITEM_NORMAL) self.memBar.Append(deitMenu, title="工具(E)") deitMenu.Append(ftpclient) deitMenu.Append(ftpserver) self.win.Bind(wx.EVT_MENU, self.ftpclient, ftpclient) # 执行退出函数 self.win.Bind(wx.EVT_MENU, self.ftpserver, ftpserver) # 执行退出函数 def ftpclient(self, event): """ ftp 客户端 """ print('ccc') def ftpserver(self, event): """ ftp 服务端 """ FTP_files().ftp_files() def agent_helpMenu_h(self): """ 菜单栏 - 帮助 :return: """ helpMenu = wx.Menu() editMenu = wx.Menu() # 初始化三级 cutItem = wx.MenuItem(editMenu, id=122, text="Cut", kind=wx.ITEM_NORMAL) # 三级 editMenu.Append(cutItem) # 添加三级 helpMenu.Append(wx.ID_ANY, "Edit", editMenu) # 二级 self.memBar.Append(helpMenu, title="帮助(H)") # 一级
2.1代码结果图示列
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Alibaba面试题:谈谈Spring用到了哪些设计模式?
前言 前几天,一位读者面阿里被问到一个问题:Spring框架用到了哪些设计模式?,答得不是很好,于是打算写篇文章讲讲这个!代理模式 所谓代理,是指它与被代理对象实现了相同的接口,客户端必须通过代理才能与被代理的目标类进行交互,而代理一般在交互的过程中(交互前后),进行某些特定的处理,比如在调用这个方法前做前置处理,调用这个方法后做后置处理。 代理又分为静态代理和动态代理两种方式,Spring的AOP采用的是动态代理的方式 Spring通过动态代理对类进行方法级别的切面增强,动态生成目标对象的代理类,并在代理类的方法中设置拦截器,通过执行拦截器中的逻辑增强了代理方法的功能,从而实现AOP。策略模式 我们前面讲到,Spring AOP是通过动态代理来实现的。 具体到代码实现,Spring支持两种动态代理实现方式,一种是JDK提供的动态代理实现方式,另一种是Cglib提供的动态代理实现方式。 Spring会在运行时动态地选择不同的动态代理实现方式。这个应用场景实际上就是策略模式的典型应用场景。 我们只需要定义一个策略接口,让不同的策略类都实现这一个策略接口。对应到Spring源码,AopPr...
- 下一篇
【Java技术探索】ThreadLocal深入浅出的源码分析(核心源码)
每日一句 一个人的成功不取决于他的智慧,而是毅力。 基本介绍 ThreadLocal是对Thread内部的局部变量ThreadLocalMap的维护类。当线程持有多个ThreadLocal的操作时,会在ThreadLocalMap中通过key进行寻找。 每个Thread里面维护了一个ThreadLocal.ThreadLocalMap变量,底层存储结构为Entry[],ThreadLocal实例作为ThreadLocalMap的key,set/get的值为Map的value,其中,key的引用为弱引用。 当执行ThreadLocal.set时,实际是将ThreadLocal对象和值通过key-value的形式放进了Thread中的ThreadLocal.ThreadLocalMap属性中,完成了线程隔离存储,保证了线程安全,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 使用场景 ThreadLocal即便你没有直接用到过,它也间接的出现在你使用过的框架里: Spring的事务管理。 Hibernate的会话管理。 logback(和log4j)中的MDC功...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS6,CentOS7官方镜像安装Oracle11G
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8编译安装MySQL8.0.19
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装