<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>luckLab</title><description>记录生活</description><link>https://luckdiy.github.io</link><item><title>Understanding Closures in JavaScript</title><link>https://luckdiy.github.io/posts/understanding-closures-in-javascript</link><guid isPermaLink="true">https://luckdiy.github.io/posts/understanding-closures-in-javascript</guid><description>A deep dive into closures and their applications in JavaScript.</description><pubDate>Tue, 01 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/e/ef/Programming_code.jpg&quot; alt=&quot;javascript code&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Closures are a fundamental concept in JavaScript that allow functions to access variables from their outer scope. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function outerFunction(outerVariable) {
  return function innerFunction(innerVariable) {
    console.log(`Outer Variable: ${outerVariable}`)
    console.log(`Inner Variable: ${innerVariable}`)
  }
}

const newFunction = outerFunction(&apos;outside&apos;)
newFunction(&apos;inside&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Closures are particularly useful for creating private variables and functions. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function Counter() {
  let count = 0
  return {
    increment: () =&amp;gt; count++,
    getCount: () =&amp;gt; count,
  }
}

const counter = Counter()
counter.increment()
console.log(counter.getCount()) // 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Closures are a powerful tool in JavaScript, enabling encapsulation and modularity.&lt;/p&gt;
</content:encoded><author>luckLab</author></item><item><title>TypeScript Generics Explained</title><link>https://luckdiy.github.io/posts/typescript-generics-explained</link><guid isPermaLink="true">https://luckdiy.github.io/posts/typescript-generics-explained</guid><description>Learn how to use generics in TypeScript to create reusable and type-safe code.</description><pubDate>Wed, 02 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Generics in TypeScript allow you to create reusable and type-safe components. Here&apos;s a simple example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function identity&amp;lt;T&amp;gt;(arg: T): T {
  return arg
}

console.log(identity&amp;lt;string&amp;gt;(&apos;Hello&apos;))
console.log(identity&amp;lt;number&amp;gt;(42))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generics can also be used with classes and interfaces:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Box&amp;lt;T&amp;gt; {
  private content: T

  constructor(content: T) {
    this.content = content
  }

  getContent(): T {
    return this.content
  }
}

const stringBox = new Box&amp;lt;string&amp;gt;(&apos;TypeScript&apos;)
console.log(stringBox.getContent())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generics are a powerful feature that can make your TypeScript code more flexible and maintainable.&lt;/p&gt;
</content:encoded><author>luckLab</author></item><item><title>Python Decorators Demystified</title><link>https://luckdiy.github.io/posts/python-decorators-demystified</link><guid isPermaLink="true">https://luckdiy.github.io/posts/python-decorators-demystified</guid><description>An introduction to Python decorators and how to use them effectively.</description><pubDate>Thu, 03 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Decorators in Python are a powerful way to modify the behavior of functions or methods. Here&apos;s a simple example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def decorator_function(original_function):
    def wrapper_function(*args, **kwargs):
        print(f&quot;Wrapper executed before {original_function.__name__}&quot;)
        return original_function(*args, **kwargs)
    return wrapper_function

@decorator_function
def say_hello():
    print(&quot;Hello!&quot;)

say_hello()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Decorators can also be used with arguments:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def greet():
    print(&quot;Hi!&quot;)

greet()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Decorators are widely used in Python for logging, access control, and more.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python -c &quot;@decorator_function\ndef say_hello():\n    print(\&quot;Hello!\&quot;)\nsay_hello()&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>Concurrency in Go</title><link>https://luckdiy.github.io/posts/concurrency-in-go</link><guid isPermaLink="true">https://luckdiy.github.io/posts/concurrency-in-go</guid><description>Explore how Go handles concurrency with goroutines and channels.</description><pubDate>Fri, 04 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Go is known for its excellent support for concurrency. The primary tools for concurrency in Go are goroutines and channels. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

func say(s string) {
    for i := 0; i &amp;lt; 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s)
    }
}

func main() {
    go say(&quot;world&quot;)
    say(&quot;hello&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Channels are used to communicate between goroutines:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c &amp;lt;- sum // send sum to channel
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)
    x, y := &amp;lt;-c, &amp;lt;-c // receive from channel

    fmt.Println(x, y, x+y)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go&apos;s concurrency model is simple yet powerful, making it a great choice for concurrent programming.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run concurrency_example.go
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>Mastering Async/Await in JavaScript</title><link>https://luckdiy.github.io/posts/mastering-async-await-in-javascript</link><guid isPermaLink="true">https://luckdiy.github.io/posts/mastering-async-await-in-javascript</guid><description>Learn how to handle asynchronous operations in JavaScript using async/await.</description><pubDate>Sat, 05 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Async/await simplifies working with asynchronous code in JavaScript. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;async function fetchData() {
  try {
    const response = await fetch(&apos;https://api.example.com/data&apos;)
    const data = await response.json()
    console.log(data)
  } catch (error) {
    console.error(&apos;Error fetching data:&apos;, error)
  }
}

fetchData()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Async/await is built on top of Promises and makes the code more readable and maintainable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node -e &quot;(async () =&amp;gt; { const response = await fetch(&apos;https://api.example.com/data&apos;); console.log(await response.json()); })()&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>TypeScript Utility Types</title><link>https://luckdiy.github.io/posts/typescript-utility-types</link><guid isPermaLink="true">https://luckdiy.github.io/posts/typescript-utility-types</guid><description>Explore the built-in utility types in TypeScript and how to use them.</description><pubDate>Sun, 06 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;TypeScript provides several utility types to make your code more concise and type-safe. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface User {
  id: number
  name: string
  email: string
}

// Partial makes all properties optional
const updateUser: Partial&amp;lt;User&amp;gt; = { name: &apos;New Name&apos; }

// Readonly makes all properties read-only
const readonlyUser: Readonly&amp;lt;User&amp;gt; = { id: 1, name: &apos;John&apos;, email: &apos;john@example.com&apos; }

// Pick selects specific properties
const userName: Pick&amp;lt;User, &apos;name&apos;&amp;gt; = { name: &apos;John&apos; }

// Omit removes specific properties
const userWithoutEmail: Omit&amp;lt;User, &apos;email&apos;&amp;gt; = { id: 1, name: &apos;John&apos; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Utility types are a great way to work with complex types in TypeScript.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;Using Partial, Readonly, Pick, and Omit in TypeScript&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>Python&apos;s List Comprehensions</title><link>https://luckdiy.github.io/posts/pythons-list-comprehensions</link><guid isPermaLink="true">https://luckdiy.github.io/posts/pythons-list-comprehensions</guid><description>Learn how to use list comprehensions in Python for concise and readable code.</description><pubDate>Mon, 07 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;List comprehensions provide a concise way to create lists in Python. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Create a list of squares
squares = [x**2 for x in range(10)]
print(squares)

# Filter even numbers
evens = [x for x in range(10) if x % 2 == 0]
print(evens)

# Nested comprehensions
matrix = [[i * j for j in range(5)] for i in range(5)]
print(matrix)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;List comprehensions are a powerful feature for creating and transforming lists in Python.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python -c &quot;print([x**2 for x in range(10)])&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>Error Handling in Go</title><link>https://luckdiy.github.io/posts/error-handling-in-go</link><guid isPermaLink="true">https://luckdiy.github.io/posts/error-handling-in-go</guid><description>Understand how to handle errors effectively in Go.</description><pubDate>Tue, 08 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Go uses a simple and explicit approach to error handling. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &quot;errors&quot;
    &quot;fmt&quot;
)

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New(&quot;division by zero&quot;)
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 0)
    if err != nil {
        fmt.Println(&quot;Error:&quot;, err)
    } else {
        fmt.Println(&quot;Result:&quot;, result)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Error handling in Go is straightforward and encourages developers to handle errors explicitly.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run error_handling.go
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>JavaScript&apos;s Event Loop Explained</title><link>https://luckdiy.github.io/posts/javascripts-event-loop-explained</link><guid isPermaLink="true">https://luckdiy.github.io/posts/javascripts-event-loop-explained</guid><description>Understand how the JavaScript event loop works and its role in asynchronous programming.</description><pubDate>Wed, 09 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The event loop is a critical part of JavaScript&apos;s runtime, enabling asynchronous programming. Here&apos;s a simple example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;console.log(&apos;Start&apos;)

setTimeout(() =&amp;gt; {
  console.log(&apos;Timeout&apos;)
}, 0)

console.log(&apos;End&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Start
End
Timeout
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The event loop ensures that the call stack is empty before executing tasks from the callback queue. This mechanism allows JavaScript to handle asynchronous operations efficiently.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node -e &quot;console.log(&apos;Start&apos;); setTimeout(() =&amp;gt; { console.log(&apos;Timeout&apos;); }, 0); console.log(&apos;End&apos;);&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>Advanced TypeScript: Conditional Types</title><link>https://luckdiy.github.io/posts/advanced-typescript-conditional-types</link><guid isPermaLink="true">https://luckdiy.github.io/posts/advanced-typescript-conditional-types</guid><description>Dive into conditional types in TypeScript and how they can enhance type safety.</description><pubDate>Thu, 10 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code&gt;echo &quot;Exploring advanced TypeScript features like conditional types&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3 Test&lt;/h2&gt;
&lt;h2&gt;#test&lt;/h2&gt;
&lt;p&gt;Conditional types in TypeScript allow you to create types based on conditions. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type IsString&amp;lt;T&amp;gt; = T extends string ? true : false

const test1: IsString&amp;lt;string&amp;gt; = true // Valid
const test2: IsString&amp;lt;number&amp;gt; = false // Valid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Conditional types are particularly useful for creating flexible and reusable type definitions.&lt;/p&gt;
</content:encoded><author>luckLab</author></item><item><title>Python&apos;s Generators and Yield</title><link>https://luckdiy.github.io/posts/pythons-generators-and-yield</link><guid isPermaLink="true">https://luckdiy.github.io/posts/pythons-generators-and-yield</guid><description>Learn how to use generators and the yield keyword in Python for efficient iteration.</description><pubDate>Fri, 11 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Generators in Python are a way to create iterators using the &lt;code&gt;yield&lt;/code&gt; keyword. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def count_up_to(n):
    count = 1
    while count &amp;lt;= n:
        yield count
        count += 1

for number in count_up_to(5):
    print(number)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generators are memory-efficient and allow you to work with large datasets without loading them entirely into memory.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python -c &quot;def count_up_to(n):\n    count = 1\n    while count &amp;lt;= n:\n        yield count\n        count += 1\nfor number in count_up_to(5):\n    print(number)&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>Go&apos;s Interfaces and Polymorphism</title><link>https://luckdiy.github.io/posts/gos-interfaces-and-polymorphism</link><guid isPermaLink="true">https://luckdiy.github.io/posts/gos-interfaces-and-polymorphism</guid><description>Explore how Go uses interfaces to achieve polymorphism.</description><pubDate>Sat, 12 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Interfaces in Go provide a way to achieve polymorphism. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

type Shape interface {
    Area() float64
}

type Circle struct {
    Radius float64
}

func (c Circle) Area() float64 {
    return 3.14 * c.Radius * c.Radius
}

type Rectangle struct {
    Width, Height float64
}

func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

func printArea(s Shape) {
    fmt.Println(&quot;Area:&quot;, s.Area())
}

func main() {
    c := Circle{Radius: 5}
    r := Rectangle{Width: 4, Height: 6}

    printArea(c)
    printArea(r)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Interfaces in Go are a powerful way to write flexible and reusable code.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;go run interfaces_example.go
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>JavaScript&apos;s Prototypal Inheritance</title><link>https://luckdiy.github.io/posts/javascript-prototypal-inheritance</link><guid isPermaLink="true">https://luckdiy.github.io/posts/javascript-prototypal-inheritance</guid><description>Learn how prototypal inheritance works in JavaScript and its use cases.</description><pubDate>Sun, 13 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Prototypal inheritance is a feature in JavaScript that allows objects to inherit properties and methods from other objects. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const parent = {
  greet() {
    console.log(&apos;Hello from parent!&apos;)
  },
}

const child = Object.create(parent)
child.greet() // Hello from parent!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prototypal inheritance is a flexible way to share behavior between objects without using classes.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node -e &quot;const parent = { greet() { console.log(&apos;Hello from parent!&apos;); } }; const child = Object.create(parent); child.greet();&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>TypeScript&apos;s keyof and Mapped Types</title><link>https://luckdiy.github.io/posts/typescripts-keyof-and-mapped-types</link><guid isPermaLink="true">https://luckdiy.github.io/posts/typescripts-keyof-and-mapped-types</guid><description>Explore the keyof operator and mapped types in TypeScript for advanced type manipulation.</description><pubDate>Mon, 14 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The &lt;code&gt;keyof&lt;/code&gt; operator and mapped types in TypeScript allow for advanced type manipulation. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;interface User {
  id: number
  name: string
  email: string
}

type UserKeys = keyof User // &apos;id&apos; | &apos;name&apos; | &apos;email&apos;

type ReadonlyUser = {
  [K in keyof User]: Readonly&amp;lt;User[K]&amp;gt;
}

const user: ReadonlyUser = {
  id: 1,
  name: &apos;John&apos;,
  email: &apos;john@example.com&apos;,
}

// user.id = 2; // Error: Cannot assign to &apos;id&apos; because it is a read-only property.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These features make TypeScript a powerful tool for creating robust and type-safe applications.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &quot;Using keyof and mapped types in TypeScript&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>Python&apos;s Context Managers and the with Statement</title><link>https://luckdiy.github.io/posts/pythons-context-managers-and-the-with-statement</link><guid isPermaLink="true">https://luckdiy.github.io/posts/pythons-context-managers-and-the-with-statement</guid><description>Learn how to use context managers and the with statement in Python for resource management.</description><pubDate>Tue, 15 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Context managers in Python are used to manage resources efficiently. Here&apos;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;with open(&apos;example.txt&apos;, &apos;w&apos;) as file:
    file.write(&apos;Hello, world!&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also create custom context managers using classes or the &lt;code&gt;contextlib&lt;/code&gt; module:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from contextlib import contextmanager

@contextmanager
def custom_context():
    print(&apos;Entering context&apos;)
    yield
    print(&apos;Exiting context&apos;)

with custom_context():
    print(&apos;Inside context&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Context managers ensure that resources are properly cleaned up, making your code more reliable and maintainable.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;python -c &quot;with open(&apos;example.txt&apos;, &apos;w&apos;) as file: file.write(&apos;Hello, world!&apos;)&quot;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>Showing Off Blog Features</title><link>https://luckdiy.github.io/posts/showing-off-blog-features</link><guid isPermaLink="true">https://luckdiy.github.io/posts/showing-off-blog-features</guid><pubDate>Sun, 20 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Since the post does not have a description in the frontmatter, the first paragraph is used.&lt;/p&gt;
&lt;h2&gt;Theming&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Use your favorite editor theme for your blog!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Theming for the website comes from builtin Shiki themes found in Expressive Code. You can view them &lt;a href=&quot;https://expressive-code.com/guides/themes/#available-themes&quot;&gt;here&lt;/a&gt;. A website can have one or more themes, defined in &lt;code&gt;src/site.config.ts&lt;/code&gt;. There are three theming modes to choose from:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;single&lt;/code&gt;: Choose a single theme for the website. Simple.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;light-dark-auto&lt;/code&gt;: Choose two themes for the website to use for light and dark mode. The header will include a button for toggling between light/dark/auto. For example, you could choose &lt;code&gt;github-dark&lt;/code&gt; and &lt;code&gt;github-light&lt;/code&gt; with a default of &lt;code&gt;&quot;auto&quot;&lt;/code&gt; and the user&apos;s experience will match their operating system theme straight away.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;select&lt;/code&gt;: Choose two or more themes for the website and include a button in the header to change between any of these themes. You could include as many Shiki themes from Expressive Code as you like. Allow users to find their favorite theme!&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;When the user changes the theme, their preference is stored in &lt;code&gt;localStorage&lt;/code&gt; to persist across page navigation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Code Blocks&lt;/h2&gt;
&lt;p&gt;Let&apos;s look at some code block styles:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def hello_world():
    print(&quot;Hello, world!&quot;)

hello_world()
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;def hello_world():
    print(&quot;Hello, world!&quot;)

hello_world()
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;python hello.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also some inline code: &lt;code&gt;1 + 2 = 3&lt;/code&gt;. Or maybe even &lt;code&gt;(= (+ 1 2) 3)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;See the &lt;a href=&quot;https://expressive-code.com/key-features/syntax-highlighting/&quot;&gt;Expressive Code Docs&lt;/a&gt; for more information on available features like wrapping text, line highlighting, diffs, etc.&lt;/p&gt;
&lt;h2&gt;Basic Markdown Elements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;List item 1&lt;/li&gt;
&lt;li&gt;List item 2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Bold text&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Italic text&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;s&gt;Strikethrough text&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.example.com&quot;&gt;Link&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In life, as in art, some endings are bittersweet. Especially when it comes to love. Sometimes fate throws two lovers together only to rip them apart. Sometimes the hero finally makes the right choice but the timing is all wrong. And, as they say, timing is everything.&lt;/p&gt;
&lt;p&gt;- Gossip Girl&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Age&lt;/th&gt;
&lt;th&gt;City&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;New York&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;Los Angeles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Charlie&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;td&gt;Chicago&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;Images&lt;/h2&gt;
&lt;p&gt;Images can include a title string after the URL to render as a &lt;code&gt;&amp;lt;figure&amp;gt;&lt;/code&gt; with a &lt;code&gt;&amp;lt;figcaption&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;PixelatedGreenTreeSide.png&quot; alt=&quot;Pixel art of a tree&quot; title=&quot;Pixel art renders poorly without proper CSS&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;![Pixel art of a tree](PixelatedGreenTreeSide.png &apos;Pixel art renders poorly without proper CSS&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&apos;ve also added a special tag for pixel art that adds the correct CSS to render properly. Just add &lt;code&gt;#pixelated&lt;/code&gt; to the very end of the alt string.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;PixelatedGreenTreeSide.png&quot; alt=&quot;Pixel art of a tree #pixelated&quot; title=&quot;But adding #pixelated to the end of the alt string fixes this&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;![Pixel art of a tree #pixelated](PixelatedGreenTreeSide.png &apos;But adding #pixelated to the end of the alt string fixes this&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Admonitions&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;:::note
testing123
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::note
testing123
:::&lt;/p&gt;
&lt;p&gt;:::tip
testing123
:::&lt;/p&gt;
&lt;p&gt;:::important
testing123
:::&lt;/p&gt;
&lt;p&gt;:::caution
testing123
:::&lt;/p&gt;
&lt;p&gt;:::warning
testing123
:::&lt;/p&gt;
&lt;h2&gt;Character Chats&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;:::duck
**Did you know?** You can easily create custom character chats for your blog with MultiTerm!
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::duck
&lt;strong&gt;Did you know?&lt;/strong&gt; You can easily create custom character chats for your blog with MultiTerm!
:::&lt;/p&gt;
&lt;h3&gt;Adding Your Own&lt;/h3&gt;
&lt;p&gt;To add your own character, first add an image file to the top-level &lt;code&gt;/public&lt;/code&gt; directory in your cloned MultiTerm repo. Astro cannot automatically optimize image assets from markdown plugins, so make sure to compress the image to a web-friendly size (&amp;lt;100kb).&lt;/p&gt;
&lt;p&gt;I recommend Google&apos;s free &lt;a href=&quot;https://squoosh.app&quot;&gt;Squoosh&lt;/a&gt; web app for creating super small webp files. The characters here have been resized to 300 pixels wide and exported to webp with 75% quality using Squoosh.&lt;/p&gt;
&lt;p&gt;After you&apos;ve added your image, update the &lt;code&gt;characters&lt;/code&gt; option in &lt;code&gt;site.config.ts&lt;/code&gt; with your newly added image file and restart the development server.&lt;/p&gt;
&lt;h3&gt;Character Conversations&lt;/h3&gt;
&lt;p&gt;When there are multiple character chats in a row, the order of the chat image and chat bubble reverses to give the chat more of a back-and-forth appearance.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:::owl
This is a cool feature!
:::

:::unicorn
I agree!
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::owl
This is a cool feature!
:::&lt;/p&gt;
&lt;p&gt;:::unicorn
I agree!
:::&lt;/p&gt;
&lt;p&gt;You can specify the alignment (&lt;code&gt;left&lt;/code&gt; or &lt;code&gt;right&lt;/code&gt;) to override the default &lt;code&gt;left, right, left, ...&lt;/code&gt; ordering.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:::unicorn{align=&quot;right&quot;}
Over here, to the right!
:::
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::unicorn{align=&quot;right&quot;}
Over here, to the right!
:::&lt;/p&gt;
&lt;h2&gt;GitHub Cards&lt;/h2&gt;
&lt;p&gt;GitHub overview cards heavily inspired by &lt;a href=&quot;https://github.com/chrismwilliams/astro-theme-cactus&quot;&gt;Astro Cactus&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::github{repo=&quot;stelcodes/multiterm-astro&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;::github{repo=&quot;stelcodes/multiterm-astro&quot;}&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;::github{user=&quot;withastro&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;::github{user=&quot;withastro&quot;}&lt;/p&gt;
&lt;h2&gt;Emoji :star_struck:&lt;/h2&gt;
&lt;p&gt;Emojis can be added in markdown by including a literal emoji character or a GitHub shortcode. You can browse an unofficial database &lt;a href=&quot;https://emojibase.dev/emojis?shortcodePresets=github&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Good morning! :sleeping: :coffee: :pancakes:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Good morning! :sleeping: :coffee: :pancakes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All emojis (both literal and shortcoded) are made more accessible by wrapping them in a &lt;code&gt;span&lt;/code&gt; tag like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;span role=&quot;img&quot; aria-label=&quot;coffee&quot;&amp;gt;☕️&amp;lt;/span&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the time of writing, &lt;a href=&quot;https://emojipedia.org/emoji-16.0&quot;&gt;emoji v16&lt;/a&gt; is not supported yet. These emojis can be included literally but they do not have shortcodes and will not be wrapped.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;LaTeX/KaTeX Math Support&lt;/h2&gt;
&lt;p&gt;You can also display inline math via &lt;a href=&quot;https://github.com/remarkjs/remark-math&quot;&gt;remark-math and rehype-katex&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Make those equations pretty! $ \frac{a}{b} \cdot b = a $
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make those equations pretty! $ \frac{a}{b} \cdot b = a $&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://katex.org/docs/supported&quot;&gt;KaTeX docs&lt;/a&gt; to learn about the syntax.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$$
a + ar + ar^2 + ar^3 + \dots + ar^{n-1} = \displaystyle\sum_{k=0}^{n - 1}ar^k = a \bigg(\dfrac{1 - r^n}{1 -r}\bigg)
$$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;$$
a + ar + ar^2 + ar^3 + \dots + ar^{n-1} = \displaystyle\sum_{k=0}^{n - 1}ar^k = a \bigg(\dfrac{1 - r^n}{1 -r}\bigg)
$$&lt;/p&gt;
&lt;h2&gt;HTML Elements&lt;/h2&gt;
&lt;p&gt;&amp;lt;button&amp;gt;A Button&amp;lt;/button&amp;gt;&lt;/p&gt;
&lt;h3&gt;Fieldset with Inputs&lt;/h3&gt;
&lt;p&gt;&amp;lt;fieldset&amp;gt;
&amp;lt;input type=&quot;text&quot; placeholder=&quot;Type something&quot;&amp;gt;&amp;lt;br&amp;gt;
&amp;lt;input type=&quot;number&quot; placeholder=&quot;Insert number&quot;&amp;gt;&amp;lt;br&amp;gt;
&amp;lt;input type=&quot;text&quot; value=&quot;Input value&quot;&amp;gt;&amp;lt;br&amp;gt;
&amp;lt;select&amp;gt;
&amp;lt;option value=&quot;1&quot;&amp;gt;Option 1&amp;lt;/option&amp;gt;
&amp;lt;option value=&quot;2&quot;&amp;gt;Option 2&amp;lt;/option&amp;gt;
&amp;lt;option value=&quot;3&quot;&amp;gt;Option 3&amp;lt;/option&amp;gt;
&amp;lt;/select&amp;gt;&amp;lt;br&amp;gt;
&amp;lt;textarea placeholder=&quot;Insert a comment...&quot;&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;br&amp;gt;
&amp;lt;label&amp;gt;&amp;lt;input type=&quot;checkbox&quot;&amp;gt; I understand&amp;lt;br&amp;gt;&amp;lt;/label&amp;gt;
&amp;lt;button type=&quot;submi&quot;&amp;gt;Submit&amp;lt;/button&amp;gt;
&amp;lt;/fieldset&amp;gt;&lt;/p&gt;
&lt;h3&gt;Form with Labels&lt;/h3&gt;
&lt;p&gt;&amp;lt;form&amp;gt;
&amp;lt;label&amp;gt;
&amp;lt;input type=&quot;radio&quot; name=&quot;fruit&quot; value=&quot;apple&quot;&amp;gt;
Apple
&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;label&amp;gt;
&amp;lt;input type=&quot;radio&quot; name=&quot;fruit&quot; value=&quot;banana&quot;&amp;gt;
Banana
&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;label&amp;gt;
&amp;lt;input type=&quot;radio&quot; name=&quot;fruit&quot; value=&quot;orange&quot;&amp;gt;
Orange
&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;label&amp;gt;
&amp;lt;input type=&quot;radio&quot; name=&quot;fruit&quot; value=&quot;grape&quot;&amp;gt;
Grape
&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;label&amp;gt;
&amp;lt;input type=&quot;checkbox&quot; name=&quot;terms&quot; value=&quot;agree&quot;&amp;gt;
I agree to the terms and conditions
&amp;lt;/label&amp;gt;&amp;lt;br&amp;gt;&lt;/p&gt;
</content:encoded><author>luckLab</author></item><item><title>bochs调试</title><link>https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/bochs%E8%B0%83%E8%AF%95</link><guid isPermaLink="true">https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/bochs%E8%B0%83%E8%AF%95</guid><description>操作系统中断的分类和处理机制。</description><pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;b 0x1500     //走到1500内存处停下来
s 1          //单步执行
n            //单步执行
show int    //开始中断跟踪
sba  17362299        //执行了多少调指令后停下来
print-stack      //打印栈&lt;/p&gt;
&lt;p&gt;00017362300:&lt;/p&gt;
&lt;p&gt;sba 17362299&lt;/p&gt;
&lt;p&gt;| STACK 0xc009efb0 [0xc0004000]
| STACK 0xc009efb4 [0x00072000]
| STACK 0xc009efb8 [0xc009eff8]
| STACK 0xc009efbc [0xc009efd0]
| STACK 0xc009efc0 [0xc0003ff4]
| STACK 0xc009efc4 [0x00000000]
| STACK 0xc009efc8 [0xc0002027]
| STACK 0xc009efcc [0xc0002275]&lt;/p&gt;
&lt;p&gt;| STACK 0xc009efd0 [0xc0000018]
| STACK 0xc009efd4 [0xc0000000]
| STACK 0xc009efd8 [0xc0090010]
| STACK 0xc009efdc [0xc0000010]
| STACK 0xc009efe0 [0x00000000]
| STACK 0xc009efe4 [0xc0001533]
| STACK 0xc009efe8 [0x00000008]
| STACK 0xc009efec [0x00000286]
| STACK 0xc009eff0 [0xc009f004]
| STACK 0xc009eff4 [0x000700f4]
| STACK 0xc009eff8 [0x00000000]
| STACK 0xc009effc [0x8ec031fa]&lt;/p&gt;
&lt;p&gt;&lt;a&gt;bochs:24&lt;/a&gt; r
eax: 0x00000020 32
ecx: 0xc0002027 -1073733593
edx: 0x00000000 0
ebx: 0xc0003ff4 -1073725452&lt;/p&gt;
&lt;p&gt;esp: 0xc009efb0 -1073090640
ebp: 0xc009eff8 -1073090568&lt;/p&gt;
&lt;p&gt;esi: 0x00072000 466944
edi: 0xc0004000 -1073725440
eip: 0xc00018f3
eflags 0x00000092: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf AF pf cf&lt;/p&gt;
&lt;p&gt;eax: 0xc0002275 -1073733003
ecx: 0xc0002027 -1073733593
edx: 0x00000000 0
ebx: 0xc0003ff4 -1073725452&lt;/p&gt;
&lt;p&gt;esp: 0xc009efe0 -1073090592
ebp: 0xc009eff8 -1073090568&lt;/p&gt;
&lt;p&gt;esi: 0x00072000 466944
edi: 0xc0004000 -1073725440
eip: 0xc00018fa
eflags 0x00000092: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf AF pf cf&lt;/p&gt;
&lt;p&gt;----------退回中断前------------&lt;/p&gt;
&lt;p&gt;| STACK 0xc009efe4 [0xc0001533]
| STACK 0xc009efe8 [0x00000008]
| STACK 0xc009efec [0x00000286]&lt;/p&gt;
&lt;p&gt;| STACK 0xc009eff0 [0xc009f004]
| STACK 0xc009eff4 [0x000700f4]
| STACK 0xc009eff8 [0x00000000]
| STACK 0xc009effc [0x8ec031fa]
| STACK 0xc009f000 [0x8ec031fa]
| STACK 0xc009f004 [0x10bb66d8]
| STACK 0xc009f008 [0x67000005]
| STACK 0xc009f00c [0x660b8b66]
| STACK 0xc009f010 [0x1274c985]
| STACK 0xc009f014 [0x438b6667]
| STACK 0xc009f018 [0x8b666704]
| STACK 0xc009f01c [0x300f0853]
| STACK 0xc009f020 [0x0cc38366]
| STACK 0xc009f024 [0xfff0e5eb]
| STACK 0xc009f028 [0xf4073c06]
| STACK 0xc009f02c [0x0000fdeb]
| STACK 0xc009f030 [0x00000000]&lt;/p&gt;
&lt;p&gt;eax: 0xc0002275 -1073733003
ecx: 0xc0002027 -1073733593
edx: 0x00000000 0
ebx: 0xc0003ff4 -1073725452
esp: 0xc009efe4 -1073090588
ebp: 0xc009eff8 -1073090568
esi: 0x00072000 466944
edi: 0xc0004000 -1073725440
eip: 0xc00018fd
eflags 0x00000086: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af PF cf&lt;/p&gt;
&lt;p&gt;es:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
cs:0x0008, dh=0x00cf9900, dl=0x0000ffff, valid=1
Code segment, base=0x00000000, limit=0xffffffff, Execute-Only, Non-Conforming, Accessed, 32-bit
ss:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=7
Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
ds:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=1
Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
fs:0x0000, dh=0x00001000, dl=0x00000000, valid=0
gs:0x0018, dh=0xc0c0930b, dl=0x80000007, valid=1
Data segment, base=0xc00b8000, limit=0x00007fff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0000, dh=0x00008b00, dl=0x0000ffff, valid=1
gdtr:base=0xc0000903, limit=0x1f
idtr:base=0x00004320, limit=0x107&lt;/p&gt;
&lt;p&gt;---------退回后--------------------
| STACK 0xc009eff0 [0xc009f004]
| STACK 0xc009eff4 [0x000700f4]
| STACK 0xc009eff8 [0x00000000]
| STACK 0xc009effc [0x8ec031fa]
| STACK 0xc009f000 [0x8ec031fa]
| STACK 0xc009f004 [0x10bb66d8]
| STACK 0xc009f008 [0x67000005]
| STACK 0xc009f00c [0x660b8b66]
| STACK 0xc009f010 [0x1274c985]
| STACK 0xc009f014 [0x438b6667]
| STACK 0xc009f018 [0x8b666704]
| STACK 0xc009f01c [0x300f0853]
| STACK 0xc009f020 [0x0cc38366]
| STACK 0xc009f024 [0xfff0e5eb]
| STACK 0xc009f028 [0xf4073c06]
| STACK 0xc009f02c [0x0000fdeb]
| STACK 0xc009f030 [0x00000000]
| STACK 0xc009f034 [0x00000000]
| STACK 0xc009f038 [0x00000000]
| STACK 0xc009f03c [0x00000000]&lt;/p&gt;
&lt;p&gt;eax: 0xc0002275 -1073733003
ecx: 0xc0002027 -1073733593
edx: 0x00000000 0
ebx: 0xc0003ff4 -1073725452
esp: 0xc009eff0 -1073090576
ebp: 0xc009eff8 -1073090568
esi: 0x00072000 466944
edi: 0xc0004000 -1073725440
eip: 0xc0001533
eflags 0x00000286: id vip vif ac vm rf nt IOPL=0 of df IF tf SF zf af PF cf&lt;/p&gt;
</content:encoded><author>luckLab</author></item><item><title>段描述符</title><link>https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%AE%B5%E6%8F%8F%E8%BF%B0%E7%AC%A6</link><guid isPermaLink="true">https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E6%AE%B5%E6%8F%8F%E8%BF%B0%E7%AC%A6</guid><description>操作系统中断的分类和处理机制。</description><pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;段描述符&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;img.png&quot; alt=&quot;img.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;段基址: 32位宽  在16-31(16) 32-29(8) 56-63(8位)&lt;/h3&gt;
&lt;h3&gt;段界限：即能寻址的最大范围(20位)(单位量)(字节/4kb)&lt;/h3&gt;
&lt;h3&gt;g: 0 1字节 1 4k  (2的20次方=1m) (1m*4k=4g)&lt;/h3&gt;
&lt;h3&gt;s: 0 系统段(不是硬件需要的都不是系统段) 1 数据段&lt;/h3&gt;
&lt;h3&gt;type: 4位  x r c a  x(执行) r(读) c(一致性) a(是否访问过) a是cpu设置的(设置为0由cpu改)&lt;/h3&gt;
&lt;h3&gt;dpl: 描述符权限级 2位 越小权限越大&lt;/h3&gt;
&lt;h3&gt;p：段是否存在 在内存中是1 不在是0 如果是0,cup会抛异常&lt;/h3&gt;
&lt;h3&gt;avl: 可用位&lt;/h3&gt;
&lt;h3&gt;l: 1 64位代码段 32是0&lt;/h3&gt;
&lt;h3&gt;D/B: d=0 16位 1 32位&lt;/h3&gt;
&lt;h3&gt;G: 指定段界限的单位大小&lt;/h3&gt;
&lt;h1&gt;gdt 段描述符表 用于存储段描述符(数组)(通过下标查找各个gd)&lt;/h1&gt;
&lt;h1&gt;gdtR 即存放gdt的寄存器,存放gdt的首地址&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;img_1.png&quot; alt=&quot;img_1.png&quot; /&gt;
gdtr寄存器 是全局描述符的指针 48位  32位gdt起始地址 16位gdt界限
只能使用lgdt指令操作&lt;/p&gt;
&lt;h1&gt;选择子&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;img_2.png&quot; alt=&quot;img_2.png&quot; /&gt;
选择子是16位数, 存放在段寄存器里(cs,ds,ss) 实模式时是段基址地址,保护模式时是选择子
保护模式 段基址地址已经存在段描述符里了,所以选择子里存放的是指向gdt里的某个段描述符的索引&lt;/p&gt;
&lt;p&gt;ti: 0 gdt(全局描述符) 1 ldt(局部描述符)
rpl: 请求特权级 2位&lt;/p&gt;
&lt;h1&gt;段描述符缓冲寄存器&lt;/h1&gt;
&lt;p&gt;目的： 段描述符在内存中,频繁访问速度较慢,所以引入段描述符缓冲寄存器&lt;/p&gt;
</content:encoded><author>luckLab</author></item><item><title>进程</title><link>https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E8%BF%9B%E7%A8%8B</link><guid isPermaLink="true">https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E8%BF%9B%E7%A8%8B</guid><description>操作系统中断的分类和处理机制。</description><pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;进程&lt;/h3&gt;
&lt;p&gt;进程 = 资源 + 线程&lt;br /&gt;
一个线程是一个执行流
进程会创建单独的页表&lt;/p&gt;
&lt;h3&gt;PCB 程序控制块(Process Control Block)&lt;/h3&gt;
&lt;p&gt;记录进程状态,PID,优先级等
&lt;img src=&quot;img_7.png&quot; alt=&quot;img_7.png&quot; /&gt;&lt;/p&gt;
</content:encoded><author>luckLab</author></item><item><title>输入系统</title><link>https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E8%BE%93%E5%85%A5%E7%B3%BB%E7%BB%9F</link><guid isPermaLink="true">https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E8%BE%93%E5%85%A5%E7%B3%BB%E7%BB%9F</guid><description>操作系统中断的分类和处理机制。</description><pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code&gt;键盘操作，当按键按下后,键盘内8048芯片通过ps/2协议发送按键码给主板上的8042芯片,8042负责触发中断,让cpu读取数据
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>页表机制</title><link>https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E9%A1%B5%E8%A1%A8</link><guid isPermaLink="true">https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E9%A1%B5%E8%A1%A8</guid><description>操作系统中断的分类和处理机制。</description><pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;分页机制&lt;/h1&gt;
&lt;p&gt;页表是凌驾于分段机制之上的,也凌驾于保护模式的段描述符之上的&lt;/p&gt;
&lt;h2&gt;逻辑地址 线性地址 和 物理地址&lt;/h2&gt;
&lt;h3&gt;逻辑地址 ds里存放选择子,通过选择子找到段描述符，段描述符映射到段基地址 :偏移量 =&amp;gt; 线性地址。&lt;/h3&gt;
&lt;h3&gt;线性地址 关闭分页 ==&amp;gt; 物理地址  开启分页 -&amp;gt; 查页目录和页表 -&amp;gt;找到物理地址&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;        ┌───────────────────────┐
        │ 逻辑地址 (Logical)     │
        │ 例如: DS:0x1234        │
        └───────────┬───────────┘
                    │
                    ▼
        ┌───────────────────────┐
        │ 段描述符 (Segmentation) │
        │ GDT/LDT 提供 Base+Limit│
        └───────────┬───────────┘
                    │
                    ▼
        ┌───────────────────────┐
        │ 线性地址 (Linear)      │
        │ Base + Offset          │
        │ 例如: 0x00401234       │
        └───────────┬───────────┘
                    │
            [分页开关 CR0.PG=1?]
                    │
    ┌───────────────┴─────────────────┐
    │                                 │
    ▼                                 ▼
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;┌─────────────────────┐           ┌──────────────────────┐
│ 分页机制关闭          │           │ 分页机制开启            │
│ Linear = Physical   │           │ 查页目录 + 页表         │
└───────────┬─────────┘           └───────────┬──────────┘
│                                 │
▼                                 ▼
┌──────────────────┐              ┌───────────────────┐
│ 物理地址 (Physical) │             │ 物理地址 (Physical) │
│ 直接访问 RAM 芯片 │                │ 页表映射后的地址    │
└──────────────────┘              └───────────────────┘&lt;/p&gt;
&lt;h2&gt;开启分页后的逻辑 =&amp;gt; 线性地址到物理地址&lt;/h2&gt;
&lt;p&gt;线性地址32位 分为三段
31-22 页目录索引 Page Directory(页目录)  用于查到目录项(pde)
21-12 页表索引  从pde里通过Page Table(pt)找到页表项(pte)
11-0 页内偏移  对应物理页的偏移量&lt;/p&gt;
&lt;p&gt;举个例子: 0x12345678  12 3 45 678&lt;/p&gt;
&lt;p&gt;12 = 18 =&amp;gt; 0001 0010
3 = 0011
pd(10bit)= 0001 0010 00 = 0100 1000 = 0x48
pt(10bit)= 11 0100 0101 = 0x345
偏移 = 0x678&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;查页目录-&amp;gt;通过0x48找到页表的物理地址&lt;/li&gt;
&lt;li&gt;查页表 -&amp;gt; 通过0x345找到页框基地址&lt;/li&gt;
&lt;li&gt;找到具体地址 -&amp;gt; 页框基地址+0x678 等到物理地址&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;物理页帧和页项&lt;/h3&gt;
&lt;p&gt;都是4k为单位,如果4g内存会划分 1m个页表项,每个页表项4字节,需要4m来存储&lt;/p&gt;
&lt;h3&gt;一级页表&lt;/h3&gt;
&lt;p&gt;段部件输出线性地址
线性地址的 高20位是索引(1m) 低12位(4k)为偏移量
查页表 -&amp;gt; 获取到页表项里的物理地址基地址
物理地址基地址+12位偏移量  -&amp;gt; 找到具体的物理地址&lt;/p&gt;
&lt;h4&gt;pte 页表项&lt;/h4&gt;
&lt;p&gt;pte 4b =&amp;gt; 32位   高20位 表示物理页框号  低12位用于权限等元数据
物理页框号*4k + 偏移量 就能找到 具体的物理内存&lt;/p&gt;
&lt;p&gt;一级页表 如果要表示4g的空间,一个pte 能表示 4k的空间，则需要 4g/4k * 4 的内存来存储
4g/4k = 1m&lt;/p&gt;
&lt;h3&gt;二级页表&lt;/h3&gt;
&lt;p&gt;一个页表项范围是4k,页尺寸不变都是4k,则一个页能有4k/4=1024个页表项
所以 4k * 1024 = 4m 代表一个页表能映射4m
4g/4m = 1024个页表,则二级页表需要有1024个页目录项
1024个页目录项*4 = 4k,则正好又等于一个物理页的大小&lt;/p&gt;
&lt;h4&gt;二级页表 页目录项&lt;/h4&gt;
</content:encoded><author>luckLab</author></item><item><title>tss任务状态段</title><link>https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/tss</link><guid isPermaLink="true">https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/tss</guid><description>操作系统中断的分类和处理机制。</description><pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;tss (Task State Segment) 任务状态段&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;tss用于记录任务切换时状态的快照,tss描述符存储在gdt中,
当前任务的tss存储在tr寄存器中
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;tss描述符格式(tss描述符并不是tss)&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;tss描述符可以获取到tss的基地址和界限
配合tss选择子才能找到真正的tss
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;img_8.png&quot; alt=&quot;img_8.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;s=0 代表系统段&lt;/li&gt;
&lt;li&gt;type-b位=1 代表任务繁忙 0 代表空闲 由cpu操作,也防止被重入&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;img_9.png&quot; alt=&quot;img_9.png&quot; /&gt;&lt;/p&gt;
</content:encoded><author>luckLab</author></item><item><title>elf可执行文件</title><link>https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/elf</link><guid isPermaLink="true">https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/elf</guid><description>操作系统中断的分类和处理机制。</description><pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;elf 是目标文件格式 就是可执行文件&lt;/h3&gt;
&lt;p&gt;+----------------------+  &amp;lt;-- 文件开头 (偏移 0)
| ELF Header (Ehdr)   |  &amp;lt;== Elf32_Ehdr 就在这里
+----------------------+
| Program Header Table |  (程序头表描述可加载的段)
+----------------------+
| Section Headers      |  (节头表描述链接器用的节)
+----------------------+
| 实际代码/数据等内容   |
+----------------------+&lt;/p&gt;
&lt;p&gt;格式是 elf头, 段头和节头,实际程序代码&lt;/p&gt;
&lt;h3&gt;elf 文件头&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;typedef struct
{
  /**
   * [0x7f,&apos;E&apos;,&apos;L&apos;,&apos;F&apos; 前4位是魔术,固定 
   * index:4 elf文件类型  5 编码格式大小端 6版本信息 7-15保留位
   * ]
  */
  unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
  Elf32_Half    e_type;                 /* Object file type 目标文件类型 2字节  */
  Elf32_Half    e_machine;              /* Architecture 指定在哪个平台运行 */
  Elf32_Word    e_version;              /* Object file version 版本信息*/
  Elf32_Addr    e_entry;                /* Entry point virtual address 运行程序的虚拟地址 */
  Elf32_Off     e_phoff;                /* Program header table file offset 用于指明程序头表*/
  Elf32_Off     e_shoff;                /* Section header table file offset 用于指明节头表 */
  Elf32_Word    e_flags;                /* Processor-specific flags 指明和处理器相关表示 */
  Elf32_Half    e_ehsize;               /* ELF header size in bytes 指明elf header的字节大小 */
  Elf32_Half    e_phentsize;            /* Program header table entry size 指明程序头表各个entry的字节大小 */
  Elf32_Half    e_phnum;                /* Program header table entry count 指明程序头表长度 */
  Elf32_Half    e_shentsize;            /* Section header table entry size 指明节头各entry的字节大小*/
  Elf32_Half    e_shnum;                /* Section header table entry count 节头长度 */
  Elf32_Half    e_shstrndx;             /* Section header string table index 用来指明string name table在节头表中的索引index */
} Elf32_Ehdr;

&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;elf 程序头结构体&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;typedef struct
{
  Elf32_Word    p_type;                 /* Segment type 段类型4字节*/
  Elf32_Off     p_offset;               /* Segment file offset 用于指明本段在文件内的起始偏移字节*/
  Elf32_Addr    p_vaddr;                /* Segment virtual address 用于指明本段在内存中的起始虚拟地址 */
  Elf32_Addr    p_paddr;                /* Segment physical address */
  Elf32_Word    p_filesz;               /* Segment size in file 本段在文件中的大小*/
  Elf32_Word    p_memsz;                /* Segment size in memory 本段在内存中的大小 */
  Elf32_Word    p_flags;                /* Segment flags 指明与本段相关的标志*/
  Elf32_Word    p_align;                /* Segment alignment 指明本段在文件和内存中的对齐方式 */
} Elf32_Phdr;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;elf文件示例&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;00000000: 7F 45 4C 46 (魔术elf) 01(32位) 01(小端) 01(当前版本) 00 00 00 00 00 00 00 00 00  .ELF............
00000010: 02 00(小端) 03 00(EM386 80386平台) 01 00 00 00(版本) 00 15 00 C0(程序的虚拟入口地址) 34 00 00 00(程序头表偏移量)  ............4...
00000020: 4C 21 00 00(节头表偏移位置)00 00 00 00(e_flag) 34 00(e_ehsize程序头位置) 20 00(段的结构体的大小) 06 00(程序头中段的个数) 28 00(节头表各个节的大小)  L!......4. ...(.
00000030: 08 00(8个节) 07 00(节头索引为7) (程序头表开始位置)01 00 00 00(可加载程序段) 00 00 00 00(本段在文件中的偏移量 0) 00 10 00 C0(本段加载到内存后的起始虚拟地址)  ................
00000040: 00 00 00 C0(0x0000c0) F4 00 00 00(0xf4本段在文件中的字节大小) F4 00 00 00(0xf400在内存中的大小) 04 00 00 00  ................
00000050: 00 10 00 00(1段) 01 00 00 00 00 05 00 00 00 15 00 C0  ................
00000060: 00 15 00 C0 18 00 00 00 18 00 00 00 05 00 00 00  ................
00000070: 00 10 00 00 01(2段) 00 00 00 00 10 00 00 00 20 00 C0  ............. ..
00000080: 00 20 00 C0 4C 00 00 00 4C 00 00 00 04 00 00 00  . ..L...L.......
00000090: 00 10 00 00 01 00(3段) 00 00 F4 1F 00 00 F4 3F 00 C0  .............?..
000000a0: F4 3F 00 C0 0C 00 00 00 0C 00 00 00 06 00 00 00  .?..............
000000b0: 00 10 00 00 51 E5 74(4段) 64 00 00 00 00 00 00 00 00  ....Q.td........
000000c0: 00 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00  ................
000000d0: 10 00 00 00 52 E5 74(5段) 64 F4 1F 00 00 F4 3F 00 C0  ....R.td.....?..
000000e0: F4 3F 00 C0 0C 00 00 00 0C 00 00 00 04 00 00 00  .?..............
000000f0: 01 00 00 00 00 00 00 00(6段) 00 00 00 00 00 00 00 00  ................
00000100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00000120: 00 00 00 00 00 00 00 00 00 00 00 00              ............
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>操作系统中断</title><link>https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E4%B8%AD%E6%96%AD</link><guid isPermaLink="true">https://luckdiy.github.io/posts/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/%E4%B8%AD%E6%96%AD</guid><description>操作系统中断的分类和处理机制。</description><pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;中断按照事件来源分类:&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;外部中断: 
   可屏蔽中断:
   不可屏蔽中断:
内部中断:
   软中断:
   异常:
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;外部中断:&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;外部中断的中断源是某个硬件,所以外部中断又称硬件中断。
比如网卡收到网络数据包,会通知cpu,cpu得到通知以后将数据拷贝到内核缓冲区。
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;外部中断 如果cpu像单片机一样都提供gpio接口,那无穷无尽的外设肯定会不够用,
所以cpu提供统一的接口作为中断信号的公共线路&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;cpu提供了两条信号线。INTR(InteRrupt)和NMI(Non Maskable Interrupt) 即可屏蔽和不可屏蔽中断(2)
&lt;img src=&quot;./img_3.png&quot; alt=&quot;./img_3.png&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;内部中断&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;软中断：即软件中断
int3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;中断描述符表 idt interrupt descriptor table&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;用于保护模式存储中断的,存中断描述符和任务门描述符和陷阱门描述符&lt;/li&gt;
&lt;li&gt;其实是存的一段代码的起始地址,所以又叫 门&lt;/li&gt;
&lt;li&gt;门 顾名思义 就是通往某个地方的大门，这里是一段程序&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4&gt;中断门&lt;/h4&gt;
&lt;p&gt;包含 中断处理程序所在的段的段选择子 和 段内偏移量  才能得到一段程序&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;linux就是使用的中断门实现的系统调用, int 0x80&lt;/li&gt;
&lt;li&gt;中断门的 type=1110
&lt;img src=&quot;img_4.png&quot; alt=&quot;img_4.png&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;中断描述符表寄存器 idtr interrupt descriptor table register&lt;/h3&gt;
&lt;p&gt;用于找到中断描述符表,6字节 48位,使用lidt 48位内存地址数据 来加载idt
&lt;img src=&quot;img_5.png&quot; alt=&quot;img_5.png&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0-15 存储idt的大小-1,最大2^16=64kb&lt;/li&gt;
&lt;li&gt;16-47 中断描述符表的地址
&lt;img src=&quot;img_6.png&quot; alt=&quot;img_6.png&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;中断发生,处理器收到 中断向量号,根据中断向量号 -&amp;gt; 中断描述符表(对应中断描述符)
中断描述符中(代码段选择子,段内偏移量)处理器加载选择子到cs,偏移量到eip,把当前的cs:eip保存到中断处理程序的栈中
还需要保存标志寄存器eflags,牵扯到特权级变化还要压入ss和esp
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;拿到中断描述符后,那cpl和选择子对应的目标代码段的dpl(在段描述符里)对比,cpl&amp;gt;dpl 表示向高特权级转移,所以处理器需要先
保存旧的ss和esp记作ss_old和esp_old,然后再tss里找到dpl级别的栈,加载到ss和esp
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>BeanDefinition 讲解</title><link>https://luckdiy.github.io/posts/spring/beandefinition</link><guid isPermaLink="true">https://luckdiy.github.io/posts/spring/beandefinition</guid><description>操作系统中断的分类和处理机制。</description><pubDate>Fri, 02 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;BeanDefinition 讲解&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Spring 源码中一个非常重要的概念：BeanDefinition&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;相关接口概念&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;BeanDefinition 是spring用来描述bean信息的元数据
BeanDefinitionRegistry beanDefinition容器，可以理解为map
BeanDefinitionReader 读取BeanDefinition 
BeanFactory bean工厂,可以创建bean
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;流程&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;BeanDefinitionReader 读取BeanDefinition,放入BeanFactory，
BeanFactory通过getBean来生成实例
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;img1.png&quot; alt=&quot;img.png&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;spring boot 注册流程&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;首先在项目启动后，
在refreshContext(刷新上下文)=&amp;gt;invokeBeanFactoryPostProcessor(工厂后置处理器)
=&amp;gt;invokeBeanDefinitionRegistryPostProcessors =&amp;gt;ConfigurationClassPostProcessor=&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded><author>luckLab</author></item><item><title>Spring Security 过滤器链解析</title><link>https://luckdiy.github.io/posts/spring/springsecurity</link><guid isPermaLink="true">https://luckdiy.github.io/posts/spring/springsecurity</guid><description>操作系统中断的分类和处理机制。</description><pubDate>Fri, 02 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Spring Security 过滤器链解析&lt;/h1&gt;
&lt;p&gt;Spring Security 的所有逻辑都是基于过滤器链的，
这里简单介绍一下 Spring Security 的过滤器链。&lt;/p&gt;
&lt;h2&gt;1. ApplicationFilterChain&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ApplicationFilterChain&lt;/code&gt; 实现了 &lt;code&gt;FilterChain&lt;/code&gt;，由 Tomcat 构建此过滤器链。&lt;/li&gt;
&lt;li&gt;由 &lt;code&gt;ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);&lt;/code&gt; 创建。&lt;/li&gt;
&lt;li&gt;过滤器列表示例：&lt;code&gt;[... DelegatingFilterProxy]&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. DelegatingFilterProxy&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DelegatingFilterProxy&lt;/code&gt; 是一个过滤器，间接注册在 &lt;code&gt;ApplicationFilterChain&lt;/code&gt; 中。&lt;/li&gt;
&lt;li&gt;它是 &lt;code&gt;WebMvcSecurityConfiguration.CompositeFilterChainProxy&lt;/code&gt; 的装饰器。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. CompositeFilterChainProxy&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CompositeFilterChainProxy&lt;/code&gt; 是 Security 真实的过滤器链。&lt;/li&gt;
&lt;li&gt;它是一个过滤器链代理，里面有 &lt;code&gt;List&amp;lt;Filter&amp;gt; doFilterDelegate&lt;/code&gt; 作为核心属性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4. doFilterDelegate 过滤器链&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;doFilterDelegate&lt;/code&gt; 会构建一个 &lt;code&gt;VirtualFilterChain&lt;/code&gt; 过滤器链，
其中包含 &lt;code&gt;[HandlerMappingIntrospector.createCacheFilter, FilterChainProxy]&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;5. FilterChainProxy&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FilterChainProxy&lt;/code&gt; 是 Spring Security 提供的过滤器链代理。&lt;/li&gt;
&lt;li&gt;其中包含 &lt;code&gt;List&amp;lt;SecurityFilterChain&amp;gt; filterChains&lt;/code&gt;，管理不同请求的不同过滤器链。&lt;/li&gt;
&lt;li&gt;通过url路径匹配具体的 &lt;code&gt;SecurityFilterChain&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;6. SecurityFilterChain&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;其实现类 &lt;code&gt;DefaultSecurityFilterChain&lt;/code&gt;，是具体的过滤器链对象。&lt;/li&gt;
&lt;li&gt;其中包含构建 &lt;code&gt;FilterChain&lt;/code&gt; 的过滤器和匹配规则。&lt;/li&gt;
&lt;li&gt;主要属性：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RequestMatcher requestMatcher&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;List&amp;lt;Filter&amp;gt; filters&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FilterChainProxy&lt;/code&gt; 通过 &lt;code&gt;requestMatcher&lt;/code&gt; 匹配 &lt;code&gt;filters&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7. VirtualFilterChain&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;VirtualFilterChain&lt;/code&gt; 是 &lt;code&gt;FilterChainProxy&lt;/code&gt; 的一个内部类。&lt;/li&gt;
&lt;li&gt;它是 &lt;code&gt;FilterChain&lt;/code&gt; 的具体实现。&lt;/li&gt;
&lt;li&gt;在第 2 步获取到过滤器后，会构建 &lt;code&gt;VirtualFilterChain&lt;/code&gt;，
这个链是真正的 Spring Security 过滤器链。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;具体参考官网的这个图片：
&lt;img src=&quot;img.png&quot; alt=&quot;img.png&quot; /&gt;&lt;/p&gt;
</content:encoded><author>luckLab</author></item><item><title>SAML 单点登录</title><link>https://luckdiy.github.io/posts/spring/saml</link><guid isPermaLink="true">https://luckdiy.github.io/posts/spring/saml</guid><description>操作系统中断的分类和处理机制。</description><pubDate>Fri, 02 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;SAML 单点登录（SSO）指南&lt;/h1&gt;
&lt;h2&gt;1. 什么是 SAML？&lt;/h2&gt;
&lt;p&gt;SAML（Security Assertion Markup Language）是一种基于 XML 的开放标准，用于在身份提供者（IdP）和服务提供者（SP）之间交换身份认证和授权数据。&lt;/p&gt;
&lt;h2&gt;2. SAML 单点登录（SSO）流程&lt;/h2&gt;
&lt;p&gt;SAML SSO 允许用户使用单个身份在多个应用程序之间进行无缝登录。典型流程如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;名称&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;sp&lt;/td&gt;
&lt;td&gt;服务提供者&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;idp&lt;/td&gt;
&lt;td&gt;身份提供者&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;用户访问 SP（服务提供者）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;例如，用户访问 &lt;code&gt;http://loclhost:8080/user&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SP 重定向到 IdP（身份提供者）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SP 生成 SAML 认证请求，并将用户重定向到 IdP（如 Okta、Keycloak、ADFS）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;用户在 IdP 认证&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户输入凭据（用户名/密码、多因素认证等）。&lt;/li&gt;
&lt;li&gt;认证成功后，IdP 生成 SAML 响应。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;IdP 返回 SAML 响应&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IdP 通过浏览器 POST SAML 断言（Assertion）到 SP 预定义的 ACS（Assertion Consumer Service）URL。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SP 解析 SAML 断言并创建会话&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SP 验证 SAML 断言的签名和有效性。&lt;/li&gt;
&lt;li&gt;解析用户信息，创建应用会话，并完成登录。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;用户成功访问受保护资源&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;认证成功后，用户可以访问 SP 的受保护页面。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;3. Spring Security SAML2 配置&lt;/h2&gt;
&lt;p&gt;实现sp过程,使用okta作为idp,配置如下:&lt;/p&gt;
&lt;h3&gt;3.1 依赖&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-security&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.security&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-security-saml2-service-provider&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.2 Spring Security 配置&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.saml2Login(Customizer.withDefaults()); // 启用 SAML 登录
        return http.build();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.3 &lt;code&gt;application.yml&lt;/code&gt; 配置&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;spring:
  security:
    saml2:
      relyingparty:
        registration:
           okta:
            assertingparty:
              metadata-uri: &quot;https://idp.元数据.idp平台生成/metadata.xml&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4.  SAML 登录 流程&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;访问 &lt;code&gt;http://localhost:8080/user&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;会经过一堆过滤器，发现未登陆以后会走到ExceptionTranslationFilter(异常拦截过滤器)&lt;/li&gt;
&lt;li&gt;ExceptionTranslationFilter 发现是匿名用户，会使用DelegatingAccessDeniedHandler处理&lt;/li&gt;
&lt;li&gt;DelegatingAccessDeniedHandler 又会委托authenticationEntryPoint 处理，saml会走到LoginUrlAuthenticationEntryPoint.commence处理&lt;/li&gt;
&lt;li&gt;LoginUrlAuthenticationEntryPoint.commence 则会重定向到 /saml2/authenticate?registrationId={registrationId}&lt;/li&gt;
&lt;li&gt;/saml2/authenticate?registrationId={registrationId} 经过 Saml2WebSsoAuthenticationRequestFilter 过滤器，会做相关处理&lt;/li&gt;
&lt;li&gt;AbstractSaml2AuthenticationRequest authenticationRequest = this.authenticationRequestResolver.resolve(request); 解析出需要请求的参数&lt;/li&gt;
&lt;li&gt;发送到 authenticationRequestUri 地址, 该地址则是idp生成的xml里的SingleSignOnService字段，也是 idp的地址&lt;/li&gt;
&lt;li&gt;idp登陆认证通过后，会调用localhost:8080/login/saml2/sso/okta接口，此接口Saml2WebSsoAuthenticationFilter会去处理&lt;/li&gt;
&lt;li&gt;Saml2WebSsoAuthenticationFilter 首先把saml的认证请求转化为Authentication,即spring_security的身份载体&lt;/li&gt;
&lt;li&gt;BaseOpenSamlAuthenticationProvider.authenticate接口处理&lt;/li&gt;
&lt;li&gt;successfulAuthentication(request, response, chain, authenticationResult); 登陆成功保存认证信息&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><author>luckLab</author></item></channel></rss>